Shell 是类 Unix 操作系统的命令解析器,用于解释执行用户输入的一连串命令,它类似于 DOS 下的 command.com 和后来 Windows 的 cmd.exe。同时 Shell 也是一种程序设计语言。作为命令解释型的脚本语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它预定义了各种环境变量,保留了一些关键字以及一些特殊字符的含义,并提供了许多在高级语言中才具有的控制结构,包括循环和分支判断。
这里再简要地介绍一下 Shell 的分类和常见的 Shell。Shell 基本分两大类:
(1)图形界面 Shell(GUI Shell, Graphical User Interface Shell)
如应用最为广泛的 Windows Explorer,以及广为人知的 Linux Shell。其中 Linux Shell 包括 X window manager (BlackBox 和 FluxBox),以及功能更强大的 CDE、GNOME、KDE、 XFCE 等。
(2)命令行式 Shell(CLI Shell, Command Line Interface Shell)
常见的命令行式 Shell,按照问世时间排序有最早的 Bourne Shell(sh)、后来的 C Shell(csh)、AT&T 公司的贝尔实验室开发的 Korn Shell (ksh)、GNU 的 Bourne Again Shell (bash)、POSIX Shell 等。我们最常见的应该是 GNU 的 bash 了。
Shell 的特殊字符非常的繁杂,各种特殊的符号在我们编写 Shell 脚本的时候如果能够用得好,往往能起到事半功倍的效果。为此,特地将shell里面的一些常见特殊符号归类并罗列成对照表的形式,以便快速的查找。看看你知道或者用过下表中你的哪些 Shell 符号呢?
Shell 常见特殊字符可以分为以下几类:特殊变量,替换符,转义字符,字符串符(引号),功能符,运算符。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
1 | $0 | 当前脚本的名称 | |
2 | $# | 传递给脚本或函数的参数个数 | |
3 | $* | 传递给脚本或函数的所有参数 | |
4 | $@ | 传递给脚本或函数的所有参数。被双引号""包含时,与 $* 稍有不同,下面将会讲到 | |
5 | $? | 上个命令的退出状态,或函数的返回值。 | |
6 | $$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 | |
7 | $n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 | |
8 | * | 作为匹配文件名扩展的一个通配符,能自动匹配给定目录下的每一个文件。 | |
9 | ~ | 波浪号(Home directory[tilde]),这个和shell环境变量$HOME是一样的。默认表示当前用户的家目录(主目录) | echo ~,查看家目录。 |
10 | - - | 两个减号,与~相同,表示当前用户的家目录(主目录) | cd - -,回到家目录。不能echo - - 来打印输出。 |
11 | ~+ | 当前的工作目录(current working directory)。这个和shell环境变量$PWD一样。 | echo ~+可以查看当前目录。 |
12 | ~- | 前一个工作目录(previous working directory)。这个和内部变量$OLDPWD一致,和减号-一样。 | echo ~-可以查看前一个工作目录。 |
13 | - | 减号。和~-一样,表示前一个工作目录。 | cd -,回到前一个工作目录,不能echo - 来查看。 |
关于上面的特殊变量的几个知识点:
(1)$@ 与 $* 的区别?
$@ 和 $* 都表示脚本或者函数传入的参数,不被双引号""包含时,都以 $1 $2 … $n 的形式输出所有参数。
但是当它们被双引号 “” 包含时,"$*"
会将所有的参数作为一个整体,以"$1 $2 … $n"
的形式输出所有参数。但是"$@"
和$@
一样,还是会将各个参数分开,以$1 $2 … $n
的形式输出所有参数。具体参考如下示例:
function print(){
echo "param num:"$#
for i in "$*"
do
echo param:$i
done
for i in "$@"
do
echo param:$i
done
echo "all param:"$*
echo "all param:"$@
echo param1:$1
echo param2:$2
return 12
}
print "lvlv0" "lvlv1"
echo $?
运行脚本,输出结果:
param num:2
param:lvlv0 lvlv1
param:lvlv0
param:lvlv1
all param:lvlv0 lvlv1
all param:lvlv0 lvlv1
param1:lvlv0
param2:lvlv1
12
替换符又分为命令替换符和变量替换符。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
14 | $ | 美元符,放在变量前用于取变量的值,比如$PATH |
|
15 | ${} | 美元符加上大括号,大括号中放变量的名称,也是用于读取变量的值 | echo ${PATH}path ,访问变量PATH,而不是变量PATHpath,注意和上面$的区别 |
16 | ${:-} | 用法${var:-word}。表示如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。 | |
17 | ${:+} | 用法${var:+word}。如果变量 var 被定义,那么返回 word,但不改变 var 的值。 | |
18 | ${:=} | 用法${var:=word}。如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 | |
19 | ${:?} | 用法${var:?message}。如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。 | |
20 | ${#} | 用法${#var}。获取字符串变量var的长度 | string="abcd";echo ${#string} #输出4 |
21 | ${:} | 字符串提取,用法${var:n} 。若n为正数,n从0开始,表示在变量var中提取第n个字符到末尾的所有字符。若n为负数,提取字符串最后面n的绝对值个字符,使用时在冒号后面加空格或一个算术表达式或整个num加上括号,如${var: -2} 、${var:1−3} 或 ${var:(-2)} 均表示提取字符串最后两个字符。 |
a="abcde";echo ${a:1-4} ,输出cde。 |
22 | ${::} | 字符串提取,用法${var:n1:n2}。 | string="tencent is a great company";echo ${string:1:4} ,输出ence。 |
23 | {,} | 用法${value1,value2,value3}。逗号分割一般用于文件列表的扩展。 | echo {a,b}.txt ,输出a.txt b.txt。 |
24 | {…} | 用法${value1…value2}。用于顺序扩展。 | touch {a..d}.txt ,结果为a.txt b.txt c.txt d.txt |
25 | ${#} | 模式匹配截断,用法${variable#pattern} 这种模式时,shell在variable中查找给定的模式pattern,如果找到,就从命令行把variable中的内容去掉左边最短的匹配模式。不改变原变量。 | var=testcase; echo ${var#*s} ,输出tcase。 |
26 | ${##} | 模式匹配截断,用法${variable##pattern} 这种模式时,shell在variable中查找给定的模式pattern,如果是存在,就从命令行把variable中的内容去掉左边最长的匹配模式。不改变原变量。 | var=testcase; echo ${var##*s} ,输出e。 |
27 | ${%} | 模式匹配截断,用法${variable%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最短的匹配模式。不改变原变量。 | var=testcase;echo ${var%s*e} ,结果为testca。 |
28 | ${%%} | 模式匹配截断,用法${variable%%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式。不改变原变量。 | var=testcase;echo ${var%%s*e} ,结果为te。 |
29 | ${/ /} | 模式匹配替换。${var/pattern/pattern}表示将var字符串的第一个匹配的pattern替换为另一个pattern。不改变原变量。 | var=/home/centos;echo ${var/o/h} 结果为/hhme/centos |
30 | ${// /} | 模式匹配替换。${var//pattern/pattern}表示将var字符串中的所有能匹配的pattern替换为另一个pattern。不改变原变量。 | var=/home/centos;echo ${var//o/h} 结果为/hhme/cenths |
31 | $[] | 整数扩展(integer expansion),在方括号内执行整数表达式并返回结果。 | a=3;b=7;echo $[$a+$b] 输出10。 |
注意: 上面的模式不符合正则表达式的规则。
序号 | 特殊符号 | 作用 | 示例 |
---|---|---|---|
33 | $() | 美元符加小括号,命令替换符,用于执行命令,替换命令的输出结果 | echo $(date) |
34 | ` ` | 一对反引号,在键盘的Tab键上面,注意与单引号的区别,其作用与$()相同 | echo `date` |
下面的转义字符都可以用在 echo 中:
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
35 | \ | 反斜杠,用于转义。 | |
36 | \a | 警报,响铃 | |
37 | \b | 退格(删除键) | |
38 | \f | 换页(FF),将当前位置移到下页开头 | |
39 | \n | 换行 | |
40 | \r | 回车 | |
41 | \t | 水平制表符(tab键) | |
42 | \v | 垂直制表符 | |
43 | \c | produce no further output,不产生进一步的输出。也就是说在\c后,这一行后面的内容都不会输出,直接删掉了 | echo -e "this is line1 \c these word will disappear" ,输出:this is line1。 |
可以使用 echo 命令的-e选项启动转义, -E 选项禁止转义,默认也是不转义的。禁止转义的话也就无法识别上面除反斜杠外的其它的转义字符了,比如echo "\n"
是不会换行的,而是输出\n,如果换行的话,使用echo -e \n
。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
45 | ‘’ | 两个单引号。单引号括住的内容,被视为常量字符串,引号内的禁止变量扩展,并且单引号字符串中不能出现单引号(对单引号使用转义符后也不行) | echo '$PATH';#输出$PATH |
46 | “” | 两个双引号。双引号包围的内容可以允许变量扩展,可以包含双引号,但需要转义。 | echo '$PATH;#输出环境变量PATH的内容 |
功能符号,我在这里把它分为两类。第一类是语法功能符,第二类是命令功能符。具体详见下文。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
48 | # | 井号。注释符号。在shell文件的行首,作为include标记,#!/bin/bash;其他地方作为注释使用。 | |
49 | ; | 分号。语句的分隔符。在shell文件一行写多条语句时,使用分号分割。 | |
50 | ;; | 双分号。在使用case选项的时候,作为每个选项的终结符。在Bash version 4+ 的时候,还可以使用[;;&], [;&] | |
51 | / | 斜杠。路径的分隔符,路径中仅有一个斜杆表示根目录,以斜杆开头的路径表示从根目录开始的路径。 | |
52 | | | 管道(pipe)。管道是Linux,Unix都有的概念,是非常基础,也是非常重要的一个概念。它的作用是将管道前(左边)的命令产生的输出(stdout)作为管道后(右边)的命令的输入(stdin)。 | less fiel\|wc -l , 用于统计文件的行数。 |
53 | > | 输出重定向。 | echo lvlv>file ,将标准输出重定向文件file中去,如果文件存在则覆盖,不能存在则创建。不指定输出的内容,>file ,则清空文件。 |
54 | >> | 输出重定向追加符。 | echo lvlv 1>>file ,将标准输出重定向文件file的最后面,不会覆盖file原有内容 |
55 | >& | 输出重定向等同符,作用于文件描述符,即左右两边的操作数是文件描述符 | echo lvlv>file 2>&1 ,标准输出重定向到文件file中,标准错误输出与标准输出重定向一致 |
56 | &> | 标准输出和标准错误输出重定向符。 | echo lvlv &>file ,标准输出和标准错误输出都重定向到文件file中,与echo lvlv 1>file 2>&1 功能相同 |
57 | < | 输入重定向 | test.sh < file ,脚本test.sh需要read的地方会从文件file读取 |
58 | << | 用法格式:cmd << text。从命令行读取输入,直到一个与text相同的行结束。除非使用引号把输入括起来,此模式将对输入内容进行shell变量替换。如果使用<<- ,则会忽略接下来输入行首的tab,结束行也可以是一堆tab再加上一个与text相同的内容。 | |
59 | <& | 标准输入重定向等同符,作用于文件描述符,即左右两边的操作数是文件描述符 | cmd <& m ,将文件描述符m作为cmd的输入,省略了标准输入描述符1,即等价于cmd 1<&fd |
60 | >&- | 关闭某个输出文件描述符。用法格式:exec fd>&- | exec >&- 或exec 0>&- ,关闭标准输出 |
61 | <&- | 关闭某个输入文件描述符。用法格式:exec fd>&- | exec <&- 或exec 1<&- 关闭标准输入 |
62 | & | 与号。如果命令后面跟上一个&符号,这个命令将会在后台运行。 | 使用格式:command& |
63 | / | 斜杠。主要有两种作用。 (1)作为路径的分隔符,路径中仅有一个斜杆表示根目录,以斜杆开头的路径表示从根目录开始的路径; (2)在作为运算符的时候,表示除法符号。 |
|
64 | () | 一对小括号。主要有两种用法: (1)命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。 (2)用于初始化数组。如:array=(a b c d) |
|
65 | {} | 一对大括号,代码块标识符。一般用于函数定义时表明函数体。 | |
66 | <<< | 三个小于号,作用就是将后面的内容作为前面命令的标准输入。 | grep a <<< "$VARIABLE" , 意思就是在VARIABLE这个变量值里查找字符a。 |
67 | >| | 大于号与竖杠。功能同>,但即便设置了noclobber属性时也会强制复盖file文件。shell设置了noclobber属性表明已存在的文件不能被重定向输出覆盖。 | |
68 | <> | 标准输入与输出重定向运算符 | exec 6<>filename ,通过exec命令,以读写的方式将文件描述符6绑定到指定文件 |
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
61 | . | 点号。 1.相当于bash内建命令source,如: #!/bin/bash; . data-file#包含data-file ;2.作为文件名的一部分,在文件名的开头,表示该文件为隐藏文件,ls一般不显示出来(ls -a 可以显示); 3.作为目录名,一个点代表当前目录,两个点号代表上层目录(当前目录的父目录)。注意,两个以上的点不出现,除非你用引号(单/双)包围作为点号字符本身; 4.正则表达式中,点号表示任意一个字符。 |
|
62 | : | 冒号。是shell的空命令(null command),什么也不做,但是返回true。用法比较多,主要有: (1)可做while死循环的条件; (2)占位符,if某一分支什么都不做的时候; (3)域分隔符,比如环境变量$PATH中,或者passwd中,都有冒号的作为域分隔符的存在; (4)清空文件。因为冒号不向标准输出任何内容,所以可以用来清空文件,示例: :>file (5)配合${:=}给未定义或为空的变量赋值,示例: : ${abc:=1234};echo $abc ,输出1234 |
Shel 的运算符比较多,大致可以分为如下几类:算数运算符、关系运算符、逻辑运算符、字符串运算符和文件运算符。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
62 | + | 加法 | a=10;b=20;expr $a + $b 结果为 30。注意空格 |
63 | - | 减法 | expr $a - $b 结果为-10 |
64 | * | 乘法 | expr $a * $b 结果为200 |
65 | / | 除法 | expr $b / $a 结果为2 |
66 | % | 取余 | expr $b % $a 结果为 0 |
67 | = | 赋值 | a=$b,将把变量 b 的值赋给 a |
68 | (()) | 双小括号算术运算符,用于 expr 命令的替代,即支持算术表达式,而无需 expr 命令 | for((i=0;i<10;++i)) 或者((out=$a*$b)) 或者if(($a==$b));then ... fi ,无需添加空格了,更加符合 C 的编程语法 |
69 | ** | 双星号(double asterisk)。算术运算中表示求幂运算 | |
70 | , | 逗号运算符,用法主要有两个: (1)用在连接一连串的数学表达式中,这串数学表达式均被求值,但只有最后一个求值结果被返回。如: (2)用于参数替代中,表示首字母小写,如果是两个逗号,则表示全部小写,注意,这个特性在bash version 4的时候被添加的。 |
示例见下文 |
逗号运算符用法示例:
(1)用在连接一连串的数学表达式中。
#!/bin/bash
t1=$((a=5+1, b=7+2))
echo t1=$t1, a=$a, b=$b
# 输出
t1=9, a=6, b=9
(2)用于参数替代中。
a="ATest"
echo ${a,}
echo ${a,,}
# 输出
aTest
atest
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
71 | [] | 一对方括号,用于判断条件是否成立 | [ $a == $b ],注意添加 4 个空格 |
72 | [[]] | 两对方括号,是对[]的扩展,可使用<、>、&&、||等运算符 | [[ $a>$b ]],只需要添加左右两边两个空格,需要注意:使用==与!=时,仍需要4个空格 |
73 | -eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 true |
74 | == | 检测两个数是否相等,作用同-eq | [ $a == $b ] 返回 true |
75 | -ne | 检测两个数是否相等,不相等返回 true。 | [ $a -ne $b ] 返回 true |
76 | != | 作用同-ne | |
77 | -gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false |
78 | -lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true |
79 | -ge | 检测左边的数是否大等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false |
80 | -le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true |
注意:
(1)运算符 [] 与 [[]] 的区别
[] 实际上是 Bash 中 test 命令的简写,即所有的 [ expression ] 等于 test expression
。而[[ expression ]]
是 Bash 中真正的条件判断语句,其语法更符合编程习惯,建议使用。
(2)Shell 中没有 <= 与 >= 运算符,只能使用-le
与-ge
替代。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
82 | ! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true |
83 | -o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true |
84 | -a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false |
85 | || | 或运算符,与&&作用相反,也有两种用法。 (1)用于条件判断,需与[[]]配合使用。两个表达式有一个为true就返回true。 (2)命令连接。command1 || command2。左边的命令返回false(即返回非0,执行失败),||右边的命令才能够被执行。 |
[[ $a < 20 || $b > 100 ]]返回true |
86 | && | 与运算符,有两种用法。 (1)用于条件判断,需与[[]]配合使用。两个表达式都为true才返回true。 (2)命令连接。command1 && command2。左边的命令返回真(即返回0,成功被执行),&&右边的命令才能够被执行。 |
[[ $a < 20 && $b > 100 ]] 返回 false |
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
87 | = | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false |
88 | != | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true |
89 | -z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false |
90 | -n | 检测字符串长度是否为0,不为0返回 true。 | [ -n $a ] 返回 true |
91 | str | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true |
92 | =~ | 正则表达式匹配运算符,用于匹配正则表达式的,配合[[]]使用 | if [[ ! $file =~ check$ ]] ,用于判断 $file 是否是以 check 结尾 |
文件运算符用于检测文件的各种属性。
序号 | 符号 | 作用 | 示例 |
---|---|---|---|
94 | -b | 文件存在且是块设备文件 | [ -b /dev/vda1 ] 返回 true |
95 | -c | 文件存在且是字符设备文件 | [ -c /dev/stdin ] 返回 true |
96 | -d | 文件存在且是目录 | [ -d / ] 返回 true |
97 | -e | 文件(包括目录)是否存在 | [ -e / ] 返回 true |
98 | -f | 文件存在且是普通文件(既不是目录,也不是设备文件) | [ -f /etc/passwd] 返回 true |
99 | -g | 文件存在且设置了 SGID 位 | [ -g /usr/bin/passwd ] 返回 false |
100 | -G | 文件存在且属于有效组 ID | [ -G /etc/passwd ] 返回 true |
101 | -h | 文件存在且是软链接。同 -L | [ -h /etc/passwd ] 返回 false |
102 | -k | 文件存在且设置了粘着位(Sticky Bit) | [ -k /tmp ] 返回 true |
103 | -L | 文件存在且是软链接。同 -h | [ -L /etc/passwd ] 返回 false |
104 | -O | 文件存在且属于有效用户ID | [ -O /etc/passwd ] 返回 true |
105 | -p | 文件存在且是具名管道 | [ -p /etc/passwd ] 返回 false |
106 | -r | 文件存在且可读 | [ -r /etc/passwd ] 返回 true |
107 | -s | 文件存在且不为空 | [ -s /etc/passwd ] 返回 true |
108 | -S | 文件存在且是套接字(socket) | [ -s /etc/passwd ] 返回 false |
109 | -u | 文件存在且设置了 SUID 位 | [ -s /usr/bin/passwd ] 返回 true |
110 | -w | 文件存在且可写 | [ -w /etc/shadow ] 返回 false |
111 | -x | 文件存在且可执行 | [ -x /usr/bin/passwd ] 返回 true |
112 | -ef | 两个文件是否为同一个文件。主要看文件设备号与 inode 是否一致 | [ /usr/bin/passwd -ef /etc/passwd ] 返回 false |
113 | -nt | 文件 FILE1 是否比 FILE2 新(修改时间新) | [ /usr/bin/passwd -nt /etc/passwd ] 返回 false |
114 | -ot | 文件 FILE1 是否比 FILE2 旧(修改时间旧) | [ /usr/bin/passwd -ot /etc/passwd ] 返回 true |
这里附带说明一下 Linux 下文件的类型。
- 普通文件
d 目录
b 块设备
c 字符设备
p 命名管道
l 符号链接
s 套接字
断断续续历时 3 个多星期,终于完成了这篇 blog,后续遇到新的特殊字符,我会及时更新。
是不是被上面的多如繁星的特殊字符弄的晕头转向,你都了解和用过吗?其实没有必要花费大量的时间去死记硬背,可当做手册参考,在需要使用的时候再去了解其意义和用法是不迟的。
Shell 的特殊字符真的是太多了,我可以很负责任的告诉你,上面总结的其实只是一部分,还有很多没有列出来。对于上面特殊字符的解释,因未参考到权威的资料,再加上本人有些字符未亲自实践和使用过,所以有些解释难免片面甚至错误,仅供参考!如有错误的地方,也请大家勿吝指教,留言告知,共同学习!如果大家在项目中使用了上面未列出的特殊字符,也请留言告知,帮助完善本篇文章,thx!
[1] Linux下高效编写Shell——shell特殊字符汇总
[2] Linux Shell脚本教程:30分钟玩转Shell脚本编程
[3] LINUX ECHO 用法 【 -E \C 体会】
[4] shell中各种括号的作用()、(())、[]、[[]]、{}
[5] 实现ll命令
[6] shell脚本中一些特殊符号
[7] linux shell数据重定向(输入重定向与输出重定向)详细分析
[8] test(1) manual
[9] 百度百科.command.com