linux shell编程之单引号,双引号和反引号的区别的区别、printf命令、退出码等讲解
一.单引号,双引号和反引号的区别的区别:
1.单引号
·由单引号括起来的字符都作为普通字符出现。特殊字符用单引号括起来以后,也会失去原有意义,而只作为普通字符解释。
·单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
2.双引号
·双引号里可以有变量
·双引号里可以出现转义字符
3.反引号
·``括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。
·反引号还可以嵌套使用。但需注意,嵌套使用时内层的反引号必须用反斜杠(\)将其转义。
·反引号内部是一个独立的bash session,其声明的变量只有在内部有效.
·反引号是一个老的用法,$()才是新的用法,如例程中的$(seq 10)。无论是在学习中,还是在实际工作中,$()都是被推荐的用法。
二.printf命令
printf 命令模仿 C 程序库(library)里的 printf() 程序。printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。
printf 命令的语法: printf format-string [arguments...]
三.退出码
shell中运行的每个命令都使用退出状态码(exit status)来告诉shell它完成了处理。退出状态码是一个0~255之间的整数值,在命令结束时由命令传回shell。
1 查看退出状态码
Linux提供了$专属变量保存上一个执行的命令的退出状态码。你可以在你运行一个命令之后查看(echo $)。
几个典型的退出状态码及其意义:
0----------------命令运行成功
1----------------通知未知错误
2----------------误用shell命令
126-------------命令不可执行
127-------------没有找到命令
128-------------无效退出参数
128+x-----------linux信号x的严重错误
130--------------命令通过Ctrl+C终止
255--------------退出状态码越界
2 exit命令
用于shell 脚本中指定退出状态码。
四.各种括号的作用()、(())、[]、[[]]、{}
1.单小括号()
(1)命令组。括号中的命令将会新开一个子shell顺序执行。
(2)与$配合使用,$(cmd)等价于`cmd`
(3)用于初始化数组。如:array=(a b c d)
2.双小括号(())
注意:只能用于整数运算或者比较,不能用于文件测试/字符串运算等场合。
(1)整数扩展。((exp))结构扩展并计算一个算术表达式的值,此计算是整数型的计算,不支持浮点型计算。如果表达式的结果为0,那么返回的退出状态码为1,或者是"false"。如果,表达式的结果为非0,那么返回的退出状态码将为0,或者是"true"。若是逻辑判断,表达式exp为真则为1,假则为0。
(2)只要括号中的运算符、表达式符合C语言运算规则,都可用在$((exp))中,甚至是三目运算符。作不同进位(如二进制、八进制、十六进制)运算时,输出结果全都自动转化成了十进制。如:echo $((16#5f)) 结果为95 (16进位转十进制)
(3)常用于算术运算比较,双括号中的变量可以不使用$符号前缀。括号内支持多个表达式用逗号分开。 只要括号中的表达式符合C语言运算规则,比如可以直接使用for((i=0;i<5;i++)), 如果不使用双括号, 则为for i in `seq 0 4`或者for i in {0..4}。再如可以直接使用if (($i<5)), 如果不使用双括号, 则为if [ $i -lt 5 ]。
(4)如果要 把双小括号的运算结果返回给shell中的变量则需要在双小括号前面加入$
(5) 只有在双小括号中才可直接使用变量,其他括号符中都需要使用$来引用变量。
3.单中括号[ ]
(1)shell的运算符都可以用单中括号[]来表示。
(2)bash 的内部命令,[和test是等同的。
(3)条件表达式要放在方括号之间,并且变量与括号之间,及变量与运算符之间都要有空格,例如:[$a==$b]是错误的,必须写成
[ $a == $b ]。
(4)[ ]中不可以使用&& || > < 等操作符号,需要使用[[ ]]来表示。
(5)在一个array 结构的上下文中,中括号用来引用数组中每个元素的编号。
4.双中括号[[ ]]
注意:不能用于数字运算或数字比较。
(1)支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式。字符串比较时可以把右边的作为一个模式,而不仅仅是一个字符串,比如[[ hello == hell ]],结果为真。[[ ]] 中匹配字符串或通配符,不需要引号。
(2)使用[[ ... ]]条件判断结构,而不是[ ... ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
(3)bash把双中括号中的表达式看作一个单独的元素,并返回一个退出状态码。
(4)双中括号中可以使用&& || > < 等操作符号,但是在[ ]中是不允许的,所有的操作符号和变量或者常量间必须要有空格否则会报错。
五.花括号{ }
1.大括号拓展.对大括号内的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。
第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
2.几种特殊的替换结构
${var:-string},${var:+string},${var:=string},${var:string}
(1)${var:-string}和${var:=string}:若变量var为空,则用在命令行中用string来替换${var:-string},否则变量var不为空时,则用变量var的值来替换${var:-string};对于${var:=string}的替换规则和${var:-string}是一样的,所不同之处是${var:=string}若var为空时,用string替换${var:=string}的同时,把string赋给变量var: ${var:=string}很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值。
(2) ${var:+string}的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量 var的值,即空值。(因为变量var此时为空,所以这两种说法是等价的)
(3) ${var:string}替换规则为:若变量var不为空,则用变量var的值来替换${var:string};若变量var为空,则把string输出到标准错误中,并从脚本中退出。我们可利用此特性来检查是否设置了变量的值。
补充扩展:在上面这五种替换结构中string不一定是常值的,可用另外一个变量的值或是一种命令的输出。
六.字符串提取
${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern}
第一种模式:${var:num},这种模式时,shell在var中提取第num个字符到末尾的所有字符。若num为正数,从左边0处开始;若num为负数,从右边开始提取字串,但必须使用在冒号后面加空格或一个数字或整个num加上括号,如${var: -2}、${var:1-3}或${var:(-2)}。
第二种模式:${var:num1:num2},num1是位置,num2是长度。表示从$var字符串的第$num1个位置开始提取长度为$num2的子串。不能为负数。
第三种模式:${var/pattern/pattern}表示将var字符串的第一个匹配的pattern替换为另一个pattern。
第四种模式:${var//pattern/pattern}表示将var字符串中的所有能匹配的pattern替换为另一个pattern。
七.shell数组
1. 数组元素定义用空格分隔,而不是逗号。如:array_string=(123 124 2345)。
2. 输出数组元素,采用 ${数组名[下标]} 格式,下标默认从0开始。如果直接输出数组名则默认于 ${数组名[0]}等价。如果要输出所有的元素,则采用“@”或“*”替代下标,即 ${数组名[@]}
八.运算符
l算数运算符
l关系运算符
l布尔运算符
l字符串运算符
l文件测试运算符
1.算术运算符
注意:
(1)条件表达式要放在方括号之间,并且要有空格,例如:[$a==$b]是错误的,必须写成
[ $a == $b ]。
(2)乘号(*)前边必须加反斜杠(\)才能实现乘法运算。
2.关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
运算符 |
说明 |
举例 |
+ |
加法 |
`expr $a + $b` 结果为30。 |
- |
减法 |
`expr $a - $b` 结果为 -10。 |
* |
乘法 |
`expr $a \* $b` 结果为 200。 |
/ |
除法 |
`expr $b / $a` 结果为2。 |
% |
取余 |
`expr $b % $a` 结果为0。 |
= |
赋值 |
a=$b 将把变量 b 的值赋给 a。 |
== |
相等。用于比较两个数字,相同则返回 true。 |
[ $a == $b ] 返回false。 |
!= |
不相等。用于比较两个数字,不相同则返回 true。 |
[ $a != $b ] 返回 true。 |
3.布尔运算符
运算符 |
说明 |
举例 |
-eq |
检测两个数是否相等,相等返回 true。 |
[ $a -eq $b ] 返回false。 |
-ne |
检测两个数是否相等,不相等返回 true。 |
[ $a -ne $b ] 返回 true。 |
-gt |
检测左边的数是否大于右边的,如果是,则返回 true。 |
[ $a -gt $b ] 返回 false。 |
-lt |
检测左边的数是否小于右边的,如果是,则返回 true。 |
[ $a -lt $b ] 返回 true。 |
-ge |
检测左边的数是否大于等于右边的,如果是,则返回 true。 |
[ $a -ge $b ] 返回 false。 |
-le |
检测左边的数是否小于等于右边的,如果是,则返回 true。 |
[ $a -le $b ] 返回 true。 |
4.逻辑运算符
运算符 |
说明 |
举例 |
! |
非运算,表达式为 true 则返回 false,否则返回 true。 |
[ ! false ] 返回 true。 |
-o |
或运算,有一个表达式为 true 则返回 true。 |
[ $a -lt 20 -o $b -gt 100 ] 返回true。 |
-a |
与运算,两个表达式都为 true 才返回 true。 |
[ $a -lt 20 -a $b -gt 100 ] 返回false。 |
5.字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
运算符 |
说明 |
举例 |
&& |
逻辑的 AND |
[[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| |
逻辑的 OR |
[[ $a -lt 100 || $b -gt 100 ]] 返回 true |
6.文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
运算符 |
说明 |
举例 |
= |
检测两个字符串是否相等,相等返回 true。 |
[ $a = $b ] 返回 false。 |
!= |
检测两个字符串是否相等,不相等返回 true。 |
[ $a != $b ] 返回true。 |
-z |
检测字符串长度是否为0,为0返回 true。 |
[ -z $a ] 返回 false。 |
-n |
检测字符串长度是否为0,不为0返回 true。 |
[ -n $a ] 返回 true。 |
str |
检测字符串是否为空,不为空返回 true。 |
[ $a ] 返回true。 |
九.test命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
1.数值测试
操作符 |
说明 |
举例 |
-b file |
检测文件是否是块设备文件,如果是,则返回 true。 |
[ -b $file ] 返回 false。 |
-c file |
检测文件是否是字符设备文件,如果是,则返回 true。 |
[ -c $file ] 返回false。 |
-d file |
检测文件是否是目录,如果是,则返回 true。 |
[ -d $file ] 返回 false。 |
-f file |
检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 |
[ -f $file ] 返回true。 |
-g file |
检测文件是否设置了 SGID 位,如果是,则返回 true。 |
[ -g $file ] 返回false。 |
-k file |
检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 |
[ -k $file ] 返回false。 |
-p file |
检测文件是否是有名管道,如果是,则返回 true。 |
[ -p $file ] 返回false。 |
-u file |
检测文件是否设置了 SUID 位,如果是,则返回 true。 |
[ -u $file ] 返回false。 |
-r file |
检测文件是否可读,如果是,则返回 true。 |
[ -r $file ] 返回true。 |
-w file |
检测文件是否可写,如果是,则返回 true。 |
[ -w $file ] 返回true。 |
-x file |
检测文件是否可执行,如果是,则返回 true。 |
[ -x $file ] 返回true。 |
-s file |
检测文件是否为空(文件大小是否大于0),不为空返回 true。 |
[ -s $file ] 返回true。 |
-e file |
检测文件(包括目录)是否存在,如果是,则返回 true。 |
[ -e $file ] 返回true。 |
num1=100
num2=100
iftest $[num1]-eq $[num2]
then
echo '两个数相等!'else
echo '两个数不相等!'
fi
2.字符串测试
参数 |
说明 |
-eq |
等于则为真 |
-ne |
不等于则为真 |
-gt |
大于则为真 |
-ge |
大于等于则为真 |
-lt |
小于则为真 |
-le |
小于等于则为真 |
3.文件测试
参数 |
说明 |
= |
等于则为真 |
!= |
不相等则为真 |
-z 字符串 |
字符串的长度为零则为真 |
-n 字符串 |
字符串的长度不为零则为真 |
iftest -e ./bash
then
echo '文件已存在!'
else
echo '文件不存在!'
fi
4.与或非
Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:"!"最高,"-a"次之,"-o"最低。
iftest -e ./notFile -o -e ./bash
then
echo '至少有一个文件存在!'
else
echo '两个文件都不存在'
fi
十.函数
[ function ] funname [()]
{
action;
[return int;]
}
1. 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2. 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
3. 函数返回值在调用该函数后通过 $ 来获得。
4.所有函数在使用前必须定义。
5.函数参数:
在Shell中,定义函数无需定义形参,在调用函数时,直接传入实参即可。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...当n>=10时,需要使用${n}来获取参数,不能直接写$10。
参数 |
说明 |
-e 文件名 |
如果文件存在则为真 |
-r 文件名 |
如果文件存在且可读则为真 |
-w 文件名 |
如果文件存在且可写则为真 |
-x 文件名 |
如果文件存在且可执行则为真 |
-s 文件名 |
如果文件存在且至少有一个字符则为真 |
-d 文件名 |
如果文件存在且为目录则为真 |
-f 文件名 |
如果文件存在且为普通文件则为真 |
-c 文件名 |
如果文件存在且为字符型特殊文件则为真 |
-b 文件名 |
如果文件存在且为块特殊文件则为真 |
十一.输入/输出重定向
参数处理 |
说明 |
$# |
传递到脚本的参数个数 |
$* |
以一个单字符串显示所有向脚本传递的参数 |
$$ |
脚本运行的当前进程ID号 |
$! |
后台运行的最后一个进程的ID号 |
$@ |
与$*相同,但是使用时加引号,并在引号中返回每个参数。 |
$- |
显示Shell使用的当前选项,与set命令功能相同。 |
$ |
显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
1.同时使用输入/输出重定向。
command1 < infile > outfile
同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中。
2.重定向深入讲解
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
实例1:如果希望 stderr 重定向到 file,可以这样写:
$ command 2 > file
实例2:如果希望 stderr 追加到 file 文件末尾,可以这样写:
$ command 2 >> file
实例3:如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
$ command > file 2>&1
或者
$ command >> file 2>&1
3. Here Document
(1)语法
command << delimiter
document
delimiter
它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。
注意:
结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
开始的delimiter前后的空格会被忽略掉。
delimiter是一个自定义标识符,只要保证前后一致即可。
4./dev/null 文件
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
如果希望屏蔽 stdout 和 stderr,可以这样写:
$ command > /dev/null 2>&1
十二.shell文件包含
1.语法
. filename # 注意点号(.)和文件名中间有一空格
或
source filename
2.实例
test2.sh代码:
#!/bin/bash
#使用 . 号来引用test1.sh 文件. 或者使用以下包含文件代码source ./test1.sh
./test1.sh
echo "菜鸟教程官网地址:$url"
注:被包含的文件 test1.sh 不需要可执行权限。
命令 |
说明 |
command > file |
将输出重定向到 file。 |
command < file |
将输入重定向到 file。 |
command >> file |
将输出以追加的方式重定向到 file。 |
n > file |
将文件描述符为 n 的文件重定向到 file。 |
n >> file |
将文件描述符为 n 的文件以追加的方式重定向到 file。 |
n >& m |
将输出文件 m 和 n 合并。 |
n <& m |
将输入文件 m 和 n 合并。 |
<< tag |
将开始标记 tag 和结束标记 tag 之间的内容作为输入。 |