1. Shell分类
简介:
普通意义上的shell就是可以接受用户输入命令的程序。它之所以被称作shell,是因为它隐藏了操作系统底层的细节。同样,Unix下的图形用户界面GNOME和KDE,有时也被叫做“虚拟shell”或“图形shell”。
分类:
Linux Shell的种类很多,目前流行的Shell包括ash、bash、ksh、csh、zsh等,种类多了,也就有了标准化的要求,这就是POSIX的由来。
可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX)是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列互相关联的标准的总称,其正式称呼为IEEE Std 1003,而国际标准名称为ISO/IEC 9945。
用户可以通过查看/etc/shells 文件中的内容来查看自己主机中当前有哪些种类的Shell,命令如下(下面是在Linux 主机中查看信息的结果):
┌──(root💀kali)-[~]
└─# cat /etc/shells 16 ⨯
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/bin/zsh
/usr/bin/zsh
/usr/bin/tmux
/usr/bin/screen
/usr/bin/pwsh
/opt/microsoft/powershell/7/pwsh
-
ash
ash Shell是由Kenneth Almquist编写的,是Linux 中占用系统资源最少的一个Shell,它只包含24个内部命令,因而使用起来很不方便。 -
bash
bash是Linux系统默认使用的Shell,它由Brian Fox 和Chet Ramey共同完成,是BourneAgain Shell的缩写,内部命令一共有40 个。Linux 使用它作为默认的Shell是因为它具有以下特色:
可以使用类似DOS下面的doskey的功能,用上下方向键查阅和快速输入并修改命令。
通过自动查找匹配的方式,给出以某字串开头的命令。
包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助信息。
ksh
ksh是Korn Shell的缩写,由Eric Gisin编写,共有42 条内部命令。该Shell最大的优点是几乎和商业发行版的ksh 完全相容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。
用于编写 script 的 shell,从可移植性和普遍性上考虑,建议用 ksh。
因为 POSIX 1003.2 就是以 ksh 为蓝本的。而 bash 又是遵循POSIX 写的。但 bash 除 linux 外,应用较少。而且,有些 ksh93 中的特性 bash 中没有,如 associative arrays。csh
csh 是Linux 比较大的内核,它由以William Joy 为代表的共计47 位作者编成,共有52个内部命令。该Shell其实是指向/bin/tcsh这样的一个Shell,也就是说,csh其实就是tcsh。zsh
zsh是Linux 最大的Shell之一,由Paul Falstad完成,共有84 个内部命令。 zsh具有如下特性:
更高效
更好的自动补全
更好的文件名展开(通配符展开)
更好的数组处理
可定制性高
如果只是一般的用途,没有必要安装这样的Shell。
查看当前用户shell:
echo $SHELL
$SHELL
是一个环境变量,它记录了Linux 当前用户所使用的Shell类型。用户可以通过直接输入各种Shell的二进制文件名(因为这些二进制文件本身是可以被执行的),来进入到该Shell下,比如进入sh可以直接输入:
┌──(root💀kali)-[~]
└─# /bin/sh
sh-5.1#
这个命令为用户又启动了一个Shell,这个Shell在最初登录的那个Shell之后,称为下级的Shell或子Shell。使用命令:
sh-5.1# exit
exit
- 可以退出这个子Shell。
2. Shell内建命令
所谓 Shell 内建命令,就是由 Bash 自身提供的命令,而不是文件系统中的某个可执行文件。
例如,
cd
命令,虽然我们一直在使用它,但如果不加以注意很难意识到它与普通命令的性质是不一样的:该命令并不是某个外部文件,只要在 Shell 中就一定可以运行这个命令。
可以使用 type
来确定一个命令是否是内建命令:
┌──(root💀kali)-[~]
└─# type cd 16 ⨯
cd is a shell builtin
┌──(root💀kali)-[~]
└─# type ifconfig
ifconfig is /usr/sbin/ifconfig
由此可见,cd
是一个 Shell 内建命令,而 ifconfig 是一个外部文件,它的位置是/usr/sbin/ifconfig。
$PATH
变量包含的目录中几乎聚集了系统中绝大多数的可执行命令,它们都是外部命令。
通常来说,内建命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘 I/O,还需要 fork创建子进程并exec
该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。
内建命令有mkdir
、cd
、touch
等等,使用 help
或者 man bash-builtins
查看内建命令
3. shell内部变量和环境变量
在shell的解析环境中存在的变量,包括全局变量和局部变量,变量前加local
成为局部变量。
例子:
#!/bin/bash
globalVar1="hello"
function test()
{
globalVar2="world"
local localVar="part" #局部变量
echo $localVar
}
#调用函数
test
echo $globalVar1 $globalVar2 $localVar
结果:
part
hello world
环境变量:
- 前言:
环境变量是操作系统环境设置的变量,适用于整个系统的用户进程;
环境变量可以在命令中设置,但是用户注销的时候将会丢失这些设置值;
若要重复适用,则最好在.profile中定义;环境变量的使用与本地变量的使用方法相同,
但是在使用之前,必须用export命令导出。
Linux中环境变量包括系统级和用户级,系统级的环境变量是每个登录到系统的用户都要读取的系统变量,而用户级的环境变量则是该用户使用系统时加载的环境变量,所以管理环境变量的文件也分为系统级和用户级的。
按变量的生存周期来划分,Linux变量可分为两类:
永久的:需要修改配置文件,变量永久生效
临时的:使用export命令声明即可,变量在关闭shell时失效
系统级:
/etc/environment
:是系统在登录时读取的第一个文件,该文件设置的是整个系统的环境,只要启动系统就会读取该文件,用于为所有进程设置环境变量。系统使用此文件时并不是执行此文件中的命令,而是根据KEY=VALUE
模式的代码,对KEY
赋值以VALUE
,因此文件中如果要定义PATH
环境变量,只需加入一行形如PATH=$PATH:/xxx/bin
的代码即可/etc/profile
:此文件是系统登录时执行的第二个文件。 为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行。并从/etc/profile.d
目录的配置文件中搜集shell的设置。(/etc/profile
可以用于设定针对全系统所有用户的环境变量,环境变量周期是永久性)
3./etc/bashrc
:是针对所有用户的bash初始化文件,在此中设定的环境变量将应用于所有用户的shell中,此文件会在用户每次打开shell时执行一次。(即每次新开一个终端,都会执行/etc/bashrc
)。
用户级(这些文件处于家目录下):
~/.profile
:对应当前登录用户的profile文件,用于定制当前用户的个人工作环境(变量是永久性),每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc
文件。这里是推荐放置个人设置的地方~/.bashrc
:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该文件被读取。(~/.bashrc只针对当前用户,变量的生命周期是永久的)
不推荐放到这儿,因为每开一个shell,这个文件会读取一次,效率肯定有影响。~/.bash_profile
or~/bash_login
:
~/.bash_profile
是交互式login 方式进入 bash 运行的,~/.bashrc
是交互式non-login
方式进入bash
运行的。通常二者设置大致相同,所以通常前者会调用后者。每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次。默认情况下,它设置一些环境变量,执行用户的.bashrc文件。(如果~/
目录下没有.bash_profile
则新建立一个)这里是推荐放置个人设置的地方
当一个shell关闭时,在.bash_profile
中定义的系统变量则会失效。因此,每打开一个新的shell时都要运行一次source bash_profile
,而且针对当前用户。~/.bash_logout
:当每次退出系统(退出bash shell)时,执行该文件。另外/etc/profile
中设定的变量(全局)可以作用于任何用户,而~/.bashrc
等中设定的变量(局部)只能继承/etc/profile
中的变量,他们是"父子"关系。
在登录Linux时要执行文件的过程如下:
在刚登录Linux时,首先启动 /etc/profile 文件,然后再启动用户目录下的 ~/.bash_profile
、 ~/.bash_login
或 ~/.profile
文件中的其中一个,用户主目录下文件的执行的顺序为:
~/.bash_profile -> ~/.bash_login -> ~/.profile
如果 ~/.bash_profile
文件存在的话,一般还会执行 ~/.bashrc
文件。
因为在 ~/.bash_profile
文件中一般会有下面的代码:
if [ -f ~/.bashrc ]; then
. ./.bashrc
fi
~/.bashrc
中,一般还会有以下代码:
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
所以,~/.bashrc
会调用 /etc/bashrc
文件。最后,在退出shell时,还会执行 ~/.bash_logout
文件。
执行顺序为:
/etc/profile -> (~/.bash_profile | ~/.bash_login | ~/.profile) -> ~/.bashrc -> /etc/bashrc -> ~/.bash_logout
/etc/profile
和/etc/environment
等各种环境变量设置文件的用处
1)先将export LANG=zh_CN
加入/etc/profile
,退出系统重新登录,登录提示显示英文。
2)先将/etc/profile
中的export LANG=zh_CN
删除,将LNAG=zh_CN
加入/etc/environment
,退出系统重新登录,登录提示显示中文。
用户环境建立的过程中总是先执行/etc/profile
,然后再读取/etc/environment
。
为什么会有如上所叙的不同呢?而不是先执行/etc/environment
,后执行/etc/profile
呢?
这是因为/etc/environment
是设置整个系统的环境,而/etc/profile
是设置所有用户的环境,前者与登录用户无关,后者与登录用户有关。
系统应用程序的执行与用户环境可以是无关的,但与系统环境是相关的,所以当你登录时,你看到的提示信息,如日期、时间信息的显示格式与系统环境的LANG
是相关的,缺省LANG=en_US
,如果系统环境LANG=zh_CN
,则提示信息是中文的,否则是英文的。
对于用户的shell初始化而言是先执行/etc/profile
,再读取文件/etc/environment
;对整个系统而言是先行/etc/environment
。
登陆系统时的顺序应该是:
/etc/enviroment --> /etc/profile -->HOME/.profile−−>HOME/.env (如果存在)
/etc/profile
是所有用户的环境变量
/etc/enviroment
是系统的环境变量
登陆系统时shell读取的顺序应该是:
/etc/profile ->/etc/enviroment -->HOME/.profile−−>HOME/.env
原因是用户环境和系统环境的区别,如果同一个变量在用户环境(/etc/profile
)和系统环境(/etc/environment
)有不同的值,那应该是以用户环境为准。
Linux中常见的环境变量有:
PATH:指定命令的搜索路径
HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
HISTSIZE:指保存历史命令记录的条数。
LOGNAME:指当前用户的登录名。
HOSTNAME:指主机的名称,许多应用程序如果要用到主机名的话,通常是从这个环境变量中来取得的。
SHELL:指当前用户用的是哪种Shell。
LANG/LANGUGE:和语言相关的环境变量,使用多种语言的用户可以修改此环境变量。
MAIL:指当前用户的邮件存放目录。
PS1:命令基本提示符,对于root用户是#,对于普通用户是$。
PS2:附属提示符,默认是“>”。
备注:可以通过修改此环境变量来修改当前的命令符,比如下列命令会将提示符修改成字符串“Hello,MyNewPrompt ”。
# PS1="Hello,My NewPrompt"
注意:上述变量的名字并不固定,如HOSTNAME在某些Linux系统中可能设置成HOST
当然,我所列举的上述环境变量并非穷尽列出!
- Linux修改和查看环境变量的命令!
echo
显示某个环境变量值echo $PATH
export
设置一个新的环境变量export HELLO="hello"
(可以无引号),在shell的命令行下直接使用[export 变量名=变量值]
定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。env
显示所有环境变量set
显示本地定义(系统中已经存在)的shell变量以及设置shell变量的新变量值,如果未指定值,则该变量值将被设为NULL。unset
清除环境变量unset HELLO
readonly
设置只读环境变量readonly HELLO
,如果使用了readonly
命令的话,变量就不可以被修改或清除。
两种方法设置环境变量
export varname=value
或者
varname=value
export varname
环境变量在进程间是父传子单向传递的
子进程对环境变量修改,不会影响父进程,例子:father.sh和son.sh
- father.sh
#!/bin/bash
export varName="father"
./son.sh
echo $varName
- son.sh
#!/bin/bash
echo $varName
export varName="son"
- ./father.sh结果:
father
father
删除变量:unset varName
4. shell的执行:
test.sh
#!/bin/sh
echo HelloWorld
cd .. #cd不影响父进程
ls
#!/bin/sh
(shebang)不可缺少
./test.sh
/bin/sh test.sh
这种方法不需要脚本有可执行权限,要有可读权限
弊端:要关注当前脚本用的什么解释器
直接在bash界面写 (
cd ..;ls -l
) 和编写shell文件效果一样source ./test.sh
不产生子进程,相当于导入窗口执行,常用于加载配置文件:source /etc/profile
,source
和.
是一样的
5. 基本语法:
-
变量赋值
VARNAME=value
等号两边不能有空格,留了空格就是一个命令+两个参数 -
使用变量
$VARNAME
或者${VARNAME}
a=1
aa="hello"
${a}a
${aa}
#使用花括号来限定变量名的范围
-
文件通配符进行文件名替换:
*
: 任意多字符
?
:任意单个字符
[若干字符]
: 匹配方括号中的某个字符,eg:ls [1-4].txt
,ls [1234].txt
- 参数拓展:
touch 1.txt 2.txt 3.txt 4.txt #等同下面的一行
touch {1,2,3,4}.txt
示例: mkdir -p day{1..10}/0{1_dog,2_cat,3_lufei}
- 命令代换:将命令的标准输出的内容变为值
#两种写法
echo `date`
echo $(date)
应用:不管在何路径调用脚本,都要在脚本所在目录创建a.txt
#!/bin/bash
absolutePath=$(cd `dirname $0`;pwd)
cd $absolutePath
touch a.txt
`为“反引号”, 如果被“反引号”括起来,表示里面需要执行的是命令。比如`dirname $0`, 就表示需要执行
dirname $0
这个命令。""
, 被双引号括起来的内容, 里面出现$
(美元符: 表示取变量名)。 `(反引号: 表示执行命令) \(转义符: 表示转义), 其余字符才表示字符串。'', 被单引号括起来的内容, 里面所有字符都表示字符串, 包括上面所说的 三个特殊字符。
在命令行状态下单纯执行 cd `dirname $0`是毫无意义的,因为它返回到/usr/bin
路径。
这个命令写在脚本文件里才有作用,他返回到这个脚本文件放置的目录,并可以根据这个目录来定位所要运行程序的相对位置(绝对位置除外)。
- $0:当前Shell程序的文件名
- dirname $0:获取当前Shell程序的路径
- cd `dirname $0`,进入当前Shell程序的目录
- 算数代换,四种写法
var=88
echo $[var+1]
echo $((var+1))
echo $[$var+1]
echo $(($var+1))
- 转义字符
echo \$SHELL #输出 SHELL
-
shell中的真假
返回0表示真,非0表示假,通过$?
获取上一条命令的返回状态
test 表达式
[ 表达式 ]
中括号是一个单独的命令,后面的参数都是作为该命令的参数
所以要留空格
( EXPRESSION )
测试该表达式是否为真
! EXPRESSION
取反
EXPRESSION1 -a EXPRESSION2
逻辑与
EXPRESSION1 -o EXPRESSION2
逻辑或
-n STRING
判断字符串不是空串
注意坑:
test -n $var
-z STRING
判断字符串长度为0
STRING1 = STRING2
判断字符串相等
STRING1 != STRING2
判断字符串不等
INTEGER1 -eq INTEGER2
判断整数相等
INTEGER1 -ge INTEGER2
判断整数1>=整数2
INTEGER1 -gt INTEGER2
判断整数1>整数2
INTEGER1 -le INTEGER2
判断整数1<=整数2
INTEGER1 -lt INTEGER2
判断整数1<整数2
INTEGER1 -ne INTEGER2
判断整数1!=整数2
FILE1 -nt FILE2
判断文件1比文件2新(指最后修改时间)
FILE1 -ot FILE2
判断文件1比文件2旧
-b FILE
块设备
-c FILE
字符设备
-d FILE
判断是否目录
-e FILE
单纯判断文件是否存在
-f FILE
判断文件是一个普通文件
-h FILE
-L FILE
判断是否一个符号链接
-k FILE
判断文件的粘着位是否被设置
-p FILE
判断文件是否是一个命名管道
-r FILE
判断文件是否有读权限
-s FILE
判断文件存在并且大小大于0字节
-S FILE
判断文件是否是一个socket文件
-t FD
判断某个文件描述符被终端打开
-w FILE
判断是否有写权限
-x FILE
有执行权限
- 分支结构
#!/bin/bash
if [ -f /bin/bash ]
then
echo "/bin/bash is a file"
else
echo "/bin/bash is not a file"
fi
:
永远为真, true
为真, false
为假
注意:如果 then 和 if 写在一行,需要加 ;
示例:
#!/bin/bash
echo "is it morning,please answer yes or no"
read YES_OR_NO #read读取用户输入
if [ $YES_OR_NO = "yes" ] #if开始
then
echo "good morning"
elif [ $YES_OR_NO = "no" ]; then
echo "good afternoon"
else
echo "not recognized"
fi #fi结束
-
shell的与、或
与的短路特性,前面条件失败,后面条件也不执行
make && sudo make install
或的特性,前面的执行成功,后面的命令就不执行了,注意与、或的区别
echo "a" || echo "b" #输出a
echo "a" && echo "b" #输出a b
- case分支
#!/bin/bash
echo "is it morning?please answer yes or no"
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES) #条件
echo "good morning"
;; #相当于break
[nN][oO])
echo "good afternoon"
;;
*)
echo "not recognized"
;;
esac #结束
-
循环语句
for循环,相当于 for value : range
#!/bin/bash
for fruit in apple banana pear
do
echo "I like $fruit"
done
从1加到100,例子:
#!/bin/bash
sum=0
for i in {1..100}
do
sum=$[sum+i]
done
echo $sum
判断文件类型:
#!/bin/bash
for f in `ls`
do
if [ -f $f ]
then
echo "$f 这是普通文件"
elif [ -d $f ]
then
echo "$f 这是目录文件"
else
echo "$f 其他类型文件"
fi
done
- 位置参数以及shift
$0 相当于C语言main函数的argv[0]
$1、$2... 这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]... (argv 是 argument vector的缩写)
$# 相当于C语言main函数的argc - 1,注意这里的#后面不表示注释,argc 是 argument count的缩写
$@ 表示参数列表"$1" "$2" ...,例如可以用在for循环中的in后面。
$* 表示参数列表"$1" "$2" ...,同上
$? 上一条命令的Exit Status
$$ 当前进程号
位置参数默认就支持10个 ,当然$@还是支持n个
可以配合shift来进行参数左移,来操作不定参数
输出
echo -n 表示不换行
echo -e 解析转义字符
echo -e "123\t234"
printf "%d\t%s\n" 123 "hello"
跟C的printf一样
-
管道:把一个命令的标准输出重定向到后面进程的标准输入
用|
符号,示例:将标准输入的内容进行缓慢向下查看,要人工操作
cat filename | more -20
比more更加完善的命令,支持回滚,也支持vim:
cat filename | less
tee
命令通过管道获取标准输出内容,然后输出到屏幕并保存到文件:ls | tee a.txt
文件重定向:
cmd > file 把标准输出重定向到新文件中
cmd >> file 追加
cmd > file 2>&1 标准出错也重定向到1所指向的file里
2>&1
文件描述符2 也重定向到文件描述符1的位置
标准错误输出也重定向到标准输出的位置
cmd >> file 2>&1
cmd < file
将file的内容重定向到cmd命令的标准输入
cmd < file1 > file2 输入输出都定向到文件里
cmd < &fd 把文件描述符fd作为标准输入
cmd > &fd 把文件描述符fd作为标准输出
cmd < &- 关闭标准输入
-
函数:
完整写法:function
或()
可以忽略其中一个,只能返回int类型的值
#!/bin/bash
function f() #function 或者 () 可以忽略其中一个,但不能同时不写
{
echo "shdfjh"
return 1
}
f
echo $?
- 函数递归遍历目录:
#!/bin/bash
function f
{
local dir="$1"
for f in `ls $1`
do
if [ -f "$dir/$f" ]
then
echo "$dir/$f is a file"
elif [ -d "$dir/$f" ]
then
echo "$dir/$f is a dir"
f "$dir/$f"
else
echo "$dir/$f is not recognized"
fi
done
}
f . #函数调用可以加参数
输出:
./assets is a dir
./assets/css is a dir
./assets/css/bulma.css is a file
./assets/css/hkzclarity.css is a file
./assets/css/hkzclarity.css.map is a file
./assets/css/prism.css is a file
./assets/css/scss is a dir
./assets/css/scss/hkzclarity.scss is a file
./assets/js is a dir
./assets/js/prism.js is a file
./author.hbs is a file
./default.hbs is a file
./error.hbs is a file
./index.hbs is a file
./LICENSE is a file
./package.json is a file
./page-about.hbs is a file
./partials is a dir
./partials/post_loop.hbs is a file
./post.hbs is a file
./README.md is a file
./screenshots is a dir
./screenshots/Author.png is a file
./screenshots/Front.png is a file
./screenshots/Mobile_Front.png is a file
- 脚本的调试:
-n 遍历一下脚本,检查语法错误
-v 一遍执行脚本一遍将解析到的脚本输出来
-x 执行脚本的同时打印每一句命令,把变量的值都打印出来 (常用)
打开调试的方法
1. bash -x 脚本.sh
2. 脚本开头 使用 #!/bin/bash -x
3. 脚本中显式的使用 set -x 打开 使用 set +x 关闭调试
- 正则表达式:
1 以S开头的字符串^S
2 以数字结尾的字符串
[0123456789] 匹配任意数字
[0-9]
\d
$ 匹配字符串结尾
[0-9]$
3 匹配空字符串(没有任何字符)
^$
4 字符串只包含三个数字
^\d\d\d$
^\d{3}$
{n} 花括号括起来一个数字,表示前面的单元重复n次
5 字符串只有3到5个字母
控制最少重复次数和最大的重复次数
{m,n} m表示前面单元最小重复次数,n表示最大重复次数
[a-zA-Z] 表示大小写字母 如果中括号中有多个区间,区间之间不要留空格或其他分隔符
^[a-zA-Z]{3,5}$
6 匹配不是a-z的任意字符
[^a-z] 中括号中第一个字符如果是^,表示区间取反
^[^a-z]$
7 字符串有0到1个数字或者字母或者下划线
{0,1} 表示重复0-1次
? 也可以表示0-1次重复
^[0-9a-zA-Z_]?$
^\w?$
8 字符串有1个或多个空白符号(\t\n\r等)
\s 表示空白字符 包括 \t\n\r ....
{1,} 表示重复1-n 跟+号一样
^\s+$
9 字符串有0个或者若干个任意字符(除了\n)
. 代表任意字符,除了\n
^.{0,}$ 花括号中两个参数置空表示重复次数任意 0-n
^.*$ *表示前面的单元重复0-n次
? 0-1
+ 1-n
* 0-n
10 匹配0或任意多组ABC,比如ABC,ABCABCABC
使用小括号来讲多个单元重新组合成为一个单元
^(ABC)*$
11 字符串要么是ABC,要么是123
| 表示选择,选择两边的正则匹配一个
^ABC$|^123$
^(ABC|123)$ 小括号也可以将选择范围控制在括号内
12 字符串只有一个点号
做转义 还是使用\
^\.$
13 匹配十进制3位整数
100 - 999
^[1-9][0-9]{2}$
匹配十进制 0-999 的数字
分段
一位数
[0-9]
两位数
10-99
[1-9][0-9]
三位数
[1-9][0-9]{2}
^([0-9]|[1-9][0-9]{1,2})$
14 匹配0-255的整数
匹配 ip
分段
一位数
[0-9]
两位数
10-99
[1-9][0-9]
三位数
100-199
1[0-9]{2}
200-249
2[0-4][0-9]
250-255
25[0-5]
15 匹配端口号
0-65535
16 email
[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?
基础的正则
+?* 是普通字符
扩展的正则
+?* 是特殊字符
perl的正则
最常用
perl正则在扩展正则之上添加了一些特殊符号
\d \w \s ....
- sort
命令从标准输入中读取数据然后按照字符串内容进行排序
-f 忽略字符大小写
-n 比较数值大小
-t 指定分割符,默认是空格或者tab
-k 指定分割后进行比较字段
-u 重复的行只显示一次
-r 反向排序
-R 打乱顺序
同样的两行洗不乱
将/etc/passwd 根据用户id来排序
sort -t: -k3 -n < /etc/passwd
- uniq
去除重复的行,前提是重复的行连续
-c 显示每行重复的次数
-d 仅显示重复过的行
-u 仅显示不曾重复的行
sort < test.txt | uniq
- wc
word count
-l 统计行数
-c 统计字节数
-w 统计单词数
- grep
global regular expression print
-c 只输出匹配行的计数
-i 不区分大小写
-H 文件名显示
-r 递归遍历目录
-n 显示行号
-s 不显示不存在或无匹配文本的错误信息
-v 显示不包含匹配文本的所有行,这个参数经常用于过滤不想显示的行
-E 使用扩展的正则表达
-P 使用perl的正则表达式
-F 匹配固定的字符串,而非正则表达式
egrep = grep -E
fgrep = grep -F
rgrep = grep -r
grep 默认使用的是基础的正则
例子:
981 grep -c sh ss.sh
983 grep -h sh ss.sh
984 grep -h -H sh ss.sh
985 grep -H sh ss.sh
987 grep -r sh .
988 grep -r -n sh .
989 rgrep -n sh .
990 man grep
994 grep -r -n -v sh .
996 grep -r -n -P sh$ .
997 grep -r -n -P ^.*bin.*$ .
999 grep -r -n ^.*bin.*$ .
1000 grep -r -n -F ^.*bin.*$ .
- find:搜索文件所在路径
find pathname -options [-print -exec -ok ...]
option 选项如下:
-name 按照文件名查找文件。注意:""不要省略,否则结果有问题
find . -name "1.txt"
find . -name "*.sh"
-perm 按照文件权限来查找文件。
find . -perm 660
-user 按照文件属主来查找文件。
-group 按照文件所属的组来查找文件。
-mtime -n +n 按照文件的更改时间来查找文件,-n表示文件更改时间距现在n天以内,+n表示文件更改时间距现在
n天以前。find命令还有-atime和-ctime 选项,但它们都和-mtime选项类似。
-atime 访问时间
-ctime 创建时间
-nogroup 查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。
-nouser 查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
-newer file1 ! file2 查找更改时间比文件file1新但比文件file2旧的文件。
-type 查找某一类型的文件,诸如:
b - 块设备文件。
d - 目录。
c - 字符设备文件。
p - 管道文件。
l - 符号链接文件。
f - 普通文件。
s - socket文件
-exec
find . -name "*.txt" -exec gzip {} \;
查找当前目录下的txt文件并且打包成为gzip
每找到一个文件,就会执行exec后面的命令
gzip ./a/2.txt
gzip ./a/6.txt
最后是一个\; 反斜杠不能省,作为当前exec后面命令的结束符
-ok
跟-exec用法一样,但是每找到一个文件要执行后面的命令前会给用户确认
-
xargs:将标准输入的参数整齐的拼凑在一行
要配合其他命令使用
docker ps -aq | xargs docker rm -f
find . -name "*.txt" | xargs -I{} mv {} xxx/
-I{} 指定一个替换字符串作为参数替换
- sed
文本1 -> sed + 脚本 -> 文本2
ed 编辑器 -> sed -> vim
sed option 'script' file1 file2 ... sed 参数 ‘脚本(/pattern/action)’ 待处理文件
sed option -f scriptfile file1 file2 ... sed 参数 –f ‘脚本文件’ 待处理文件
p, print 打印
a, append 追加
i, insert 插入
d, delete 删除
s, substitution 替换
- awk
awk option 'script' file1 file2 ...
awk option -f scriptfile file1 file2 ...
最常见用法就是过滤哪一列
xxxx | awk '{print $2}'
脚本格式
{actions}
每一行文本都无条件的执行脚本
/pattern/{actions}
匹配了模式之后再执行后面的动作
condition{actions}
BEGIN
在遍历文本的第一行之前会执行某个动作
END
在遍历完文本之后再去执行某个动作
ProductA 30
ProductB 76
ProductC 55
在输出表格之前输出表头 产品名字 库存
输出完表格之后 输出 库存总量 : xxxx
在遍历之前输出表头
BEGIN{
printf "%s\t%s\n","产品","库存";
sum=0;
}
在遍历每一行的过程中输出每一行的内容,将库存加到sum变量
{
printf "%s\t%s\n",$1,$2;
sum+=$2;
}
遍历完之后输出sum变量
END{
printf "库存总量:%d\n",sum
}
- crontab
linux 系统定时器
需求,每天什么时候去做什么事情
/etc/crontab
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )