最近自己写了一个Shell脚本,来实现项目中的一些简单应用,现在脚本写完了,把这个过程中用到的Shell编程知识记录下来,方便以后查阅。
1、变量
要说的只是一个简单的小错误:变量赋值时不要加'$'符号,引用的时候才需要加,否则Shell会把'='左边替换成变量的实际内容;
2、函数
函数必需在使用它之前定义,所以,Shell脚本一般都将函数的定义放在脚本的头部。
函数定义格式:
name()
{
statements...
}
可以在函数体中使用return来跳出并返回一个值。
函数调用的时候只写函数名称就可以,不要加'()'
获取函数的返回值,只能通过在函数调用完成后马上检查 $? 来获取,注意这之间最好不要有其它操作,以免 $? 被改写
要注意的是,一定要避免我们在使用C语言时的习惯,当我们用一个变量直接等于一个函数,并期望这个变量得到函数的返回值时,这其实是错误的。Shell不会主动将函数的返回值赋与一个等待接收的变量,而要我们自己在调用函数完成后,将$?赋与变量,举例:
func_call
RET_VALUE=$?
函数中也可以使用参数,此时格式与获得脚本参数一要,比如 $1 代表函数的第1个参数等。
3、数值计算
Shell脚本中,直接使用 1+3 并不会返回4,而是返回"1+3"这个字符串,如果需要做计算的话,可以使用 $[]表达式,比如:
$[1+2]将得到结果3,其中也可以使用变量
不过,Shell中只能计算整数,不支持小数的计算和比较。如果需要操作小数,可以通过bc命令来完成,例:
echo "1.0+2.5*3" | bc -l
将返回结果8.5
比较两个小数的大小时,Shell也不能直接完成,可以通过awk来进行比较,请参考后面对awk的介绍
3、条件判断
我基本上都是通过test来完成的条件判断,详细的test使用方法可以参考man文档,下面列几个常用的和注意事项:
基本格式:test "a" = "b"
注意,在使用test时,如果条件成立,则test 的退出状态码为0,否则为1;test表达式中的判断符号两边都要留出空格。
判断符号:
= 用来判断两个字符串是否相同
-z 判断字符串是否为空,格式:test -z ""
-n 判断字符串是否非空
-eq 用来判断两个数字是否相等
-ne 两个数字是否不同
-gt 前一个数字是否大于后面的数字
有一个问题需要注意一下,那就是我们在比较字符串时,如果比较的双方中任意一方是变量的话,那么要做一下特殊处理,比如:
比较 $1 是否是 shutdown :
if test "$1" = "shutdown" ; then ....
而不是这样:
if test $1 = "shutdown" ; then ....
原因是,如果$1为空的话,第二种写法就被替换成了:
if test = "shutdown" ; then ....
于是,在脚本解释过程中,就是出现错误。同样,也有这种写法:
test "x$1" = "shutdown" 或 test x$1 = "shutdown" 都可以。同样的问题出现在判断字符串是否为空时,一定要这样:
test -z "$1" 而不是直接的 test -z $1,道理和前面是一样的。
3、for循环格式
基本格式为:
for cond ; do
statement...
done
其中,cond可以直接从一个列表中取,比如:
for str in "abc" "def" "ghi" ; do
echo $str
done
可以依次输出三个字符串。
可以通过$*来获得所有的参数列表,即遍历每个参数
in 后面也可以是其它命令的执行结果,比如
for item in `ls` 将得到当前目录中的每一项等
3、if格式
基本格式:
if cond ; then
...
elif cond ; then
...
else
...
fi
可以将then换到下一行,这时应该去掉';'分号。
其中,cond可以是一个test表达式,test执行成功的话,即代表if条件满足。
3、case格式
case相当于C语言中的switch,基本格式为:
case var in
value1)
....
;;
value2)
....
;;
*)
....
;;
esac
其中,value1/2是不同的判断分支,每个分支以;;结束,case语句最后以esac结束。
在value判断分支中,可以使用Linux下的通配符,比如*,?,[]等
3、echo的使用
其实echo的使用不只是Shell编程中可以用到。默认情况下,echo会回显后面的所有字符,并自动换行。
-n选项可以用来禁止echo自动换行
-e选项可以识别出输出字符串上的转义字符,比如"\n"
还有些选项可以参考echo的man文档
4、cut使用
cut可以用来截断字符串,比如:echo "abc" | cut -b1-2 结果将为 ab
常用参数:
-b 以字符计算,后面的1-2说明为第1个到第2个字符,还可以为1-3等
如果需要第3个以后所有字符,则为 cut -b3- 即可,如果是前3个字符,也可以写成 cut -b-3
5、find使用
find用来查找满足条件的文件,基本格式为:
find path option
path为开始查找的目录,注意,默认情况下find是进行递归查找的
option可以定义查找的条件,常用的选项有:
-name 限定名称,可以使用通配符,不过要用双引号引起来,比如 find . -name "*.bak"
-atime, -mtime, -ctime 分配代表文件最后的访问时间、修改时间、属性修改的时间,可以在后面添加具体的时间限制,比如:
find . -mtime +1
即查找1天之前被修改的文件。相应的,-1为1天之内,1即为精确的“第1天”修改的文件
find中的天数计算很让我头晕,在它的说明文档里,写明“+1意味着至少2天以前”,后来我终于总结出了它的时间计算方法,即:
0 代表0~24小时
1 代表24~48小时
+1 代表48小时以上,即两天以上
-1 代表24小时以下
6、awk使用
awk似乎是很强大的一个工具,我只用到了一个很小的功能,就是取一行文件的某个字段。基本格式:
echo "a b c" | awk '{print $2}'
将返回字符中的第2个字段,即b
awk默认用空格做为字段间的分隔符,可以通过 -F选项进行修改,比如:
echo "a,b,c" | awk -F, '{print $2}'
同样将返回b
awk还可以进行小数的比较,格式如下:
echo "1.2 2.3" | awk '($1<$2){exit 1}'
执行后没有输出,但可以通过检查返回值来进行判断,此时,$? 值为1,如果$1<$2的条件没有满足,返回值应该为0
7、Linux终端下的彩色字符
通过一些转义字符,可以让黑白的字符显示也带上颜色。
\033[ 代表了转义字符序列的开始,后面跟上几个数字来设置字符显示方式和前景、背景颜色,再加上m字符结束。比如:
\033[32m将后面的字符都以红色输出。具体数值代表的意义为:
前景颜色数值 背景颜色数值 代表颜色
------------------------------------------
30 40 黑色
31 41 红色
32 42 绿色
33 43 黃色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色
另外还有字符显示控制:
数值 效果
--------------------------
0 终端默认设置
1 高亮显示
4 使用下划线
5 闪烁
7 反白显示
8 不可见
以上几类可以同时使用,即可以同时设置前景色、背景色,但同一类只能设置一次。举例:
\033[32;40m
将后面的字符以黑底红字显示。显示结束后,一定要记得恢复终端的默认显示:
\033[0m;
下面将在括号里显示个红色的OK:
echo -e "[ \033[32mOK\033[0m ]"
-e选项的含意是支持转义字符,详见上面对echo的说明
1、变量
要说的只是一个简单的小错误:变量赋值时不要加'$'符号,引用的时候才需要加,否则Shell会把'='左边替换成变量的实际内容;
2、函数
函数必需在使用它之前定义,所以,Shell脚本一般都将函数的定义放在脚本的头部。
函数定义格式:
name()
{
statements...
}
可以在函数体中使用return来跳出并返回一个值。
函数调用的时候只写函数名称就可以,不要加'()'
获取函数的返回值,只能通过在函数调用完成后马上检查 $? 来获取,注意这之间最好不要有其它操作,以免 $? 被改写
要注意的是,一定要避免我们在使用C语言时的习惯,当我们用一个变量直接等于一个函数,并期望这个变量得到函数的返回值时,这其实是错误的。Shell不会主动将函数的返回值赋与一个等待接收的变量,而要我们自己在调用函数完成后,将$?赋与变量,举例:
func_call
RET_VALUE=$?
函数中也可以使用参数,此时格式与获得脚本参数一要,比如 $1 代表函数的第1个参数等。
3、数值计算
Shell脚本中,直接使用 1+3 并不会返回4,而是返回"1+3"这个字符串,如果需要做计算的话,可以使用 $[]表达式,比如:
$[1+2]将得到结果3,其中也可以使用变量
不过,Shell中只能计算整数,不支持小数的计算和比较。如果需要操作小数,可以通过bc命令来完成,例:
echo "1.0+2.5*3" | bc -l
将返回结果8.5
比较两个小数的大小时,Shell也不能直接完成,可以通过awk来进行比较,请参考后面对awk的介绍
3、条件判断
我基本上都是通过test来完成的条件判断,详细的test使用方法可以参考man文档,下面列几个常用的和注意事项:
基本格式:test "a" = "b"
注意,在使用test时,如果条件成立,则test 的退出状态码为0,否则为1;test表达式中的判断符号两边都要留出空格。
判断符号:
= 用来判断两个字符串是否相同
-z 判断字符串是否为空,格式:test -z ""
-n 判断字符串是否非空
-eq 用来判断两个数字是否相等
-ne 两个数字是否不同
-gt 前一个数字是否大于后面的数字
有一个问题需要注意一下,那就是我们在比较字符串时,如果比较的双方中任意一方是变量的话,那么要做一下特殊处理,比如:
比较 $1 是否是 shutdown :
if test "$1" = "shutdown" ; then ....
而不是这样:
if test $1 = "shutdown" ; then ....
原因是,如果$1为空的话,第二种写法就被替换成了:
if test = "shutdown" ; then ....
于是,在脚本解释过程中,就是出现错误。同样,也有这种写法:
test "x$1" = "shutdown" 或 test x$1 = "shutdown" 都可以。同样的问题出现在判断字符串是否为空时,一定要这样:
test -z "$1" 而不是直接的 test -z $1,道理和前面是一样的。
3、for循环格式
基本格式为:
for cond ; do
statement...
done
其中,cond可以直接从一个列表中取,比如:
for str in "abc" "def" "ghi" ; do
echo $str
done
可以依次输出三个字符串。
可以通过$*来获得所有的参数列表,即遍历每个参数
in 后面也可以是其它命令的执行结果,比如
for item in `ls` 将得到当前目录中的每一项等
3、if格式
基本格式:
if cond ; then
...
elif cond ; then
...
else
...
fi
可以将then换到下一行,这时应该去掉';'分号。
其中,cond可以是一个test表达式,test执行成功的话,即代表if条件满足。
3、case格式
case相当于C语言中的switch,基本格式为:
case var in
value1)
....
;;
value2)
....
;;
*)
....
;;
esac
其中,value1/2是不同的判断分支,每个分支以;;结束,case语句最后以esac结束。
在value判断分支中,可以使用Linux下的通配符,比如*,?,[]等
3、echo的使用
其实echo的使用不只是Shell编程中可以用到。默认情况下,echo会回显后面的所有字符,并自动换行。
-n选项可以用来禁止echo自动换行
-e选项可以识别出输出字符串上的转义字符,比如"\n"
还有些选项可以参考echo的man文档
4、cut使用
cut可以用来截断字符串,比如:echo "abc" | cut -b1-2 结果将为 ab
常用参数:
-b 以字符计算,后面的1-2说明为第1个到第2个字符,还可以为1-3等
如果需要第3个以后所有字符,则为 cut -b3- 即可,如果是前3个字符,也可以写成 cut -b-3
5、find使用
find用来查找满足条件的文件,基本格式为:
find path option
path为开始查找的目录,注意,默认情况下find是进行递归查找的
option可以定义查找的条件,常用的选项有:
-name 限定名称,可以使用通配符,不过要用双引号引起来,比如 find . -name "*.bak"
-atime, -mtime, -ctime 分配代表文件最后的访问时间、修改时间、属性修改的时间,可以在后面添加具体的时间限制,比如:
find . -mtime +1
即查找1天之前被修改的文件。相应的,-1为1天之内,1即为精确的“第1天”修改的文件
find中的天数计算很让我头晕,在它的说明文档里,写明“+1意味着至少2天以前”,后来我终于总结出了它的时间计算方法,即:
0 代表0~24小时
1 代表24~48小时
+1 代表48小时以上,即两天以上
-1 代表24小时以下
6、awk使用
awk似乎是很强大的一个工具,我只用到了一个很小的功能,就是取一行文件的某个字段。基本格式:
echo "a b c" | awk '{print $2}'
将返回字符中的第2个字段,即b
awk默认用空格做为字段间的分隔符,可以通过 -F选项进行修改,比如:
echo "a,b,c" | awk -F, '{print $2}'
同样将返回b
awk还可以进行小数的比较,格式如下:
echo "1.2 2.3" | awk '($1<$2){exit 1}'
执行后没有输出,但可以通过检查返回值来进行判断,此时,$? 值为1,如果$1<$2的条件没有满足,返回值应该为0
7、Linux终端下的彩色字符
通过一些转义字符,可以让黑白的字符显示也带上颜色。
\033[ 代表了转义字符序列的开始,后面跟上几个数字来设置字符显示方式和前景、背景颜色,再加上m字符结束。比如:
\033[32m将后面的字符都以红色输出。具体数值代表的意义为:
前景颜色数值 背景颜色数值 代表颜色
------------------------------------------
30 40 黑色
31 41 红色
32 42 绿色
33 43 黃色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色
另外还有字符显示控制:
数值 效果
--------------------------
0 终端默认设置
1 高亮显示
4 使用下划线
5 闪烁
7 反白显示
8 不可见
以上几类可以同时使用,即可以同时设置前景色、背景色,但同一类只能设置一次。举例:
\033[32;40m
将后面的字符以黑底红字显示。显示结束后,一定要记得恢复终端的默认显示:
\033[0m;
下面将在括号里显示个红色的OK:
echo -e "[ \033[32mOK\033[0m ]"
-e选项的含意是支持转义字符,详见上面对echo的说明