介绍编写shell脚本的常用技巧,以及一些实用的脚本片段。
¶参数
| 变量 | 说明 |
|---|---|
$# |
参数的个数 |
$* / $@ |
所有参数 |
$0 |
第0个参数,一般是脚本文件名 |
$1 |
第1个参数,其余参数依次类推 |
$$ |
当前进程ID |
$*和$@没被双引号括起来的时候,是没区别的,将每个参数看作一份数据,用空格分隔。如果用双引号括起来,"$*"将所有参数看作一个整体,"$@"依旧将每个参数看作一份数据。可以用for循环体现出差别。
脚本将所有的特殊变量都打印出来。
1 | !/bin/bash |
执行的输出示例如下。
1 | [root@pkserver test]# ./special_variable.sh 1 2 3 4 5 6 |
¶返回值
exit命令用于结束脚本的运行。可以接一个参数,表示脚本的放回值。一般用0表示正常结束,非0表示异常。通过遍历$?可以获取脚本返回值。如下是示例。
1 | !/bin/bash |
示例输出
1 | [root@pkserver test]# ./exit.sh |
¶流程控制语句
¶条件语句if
if语句的基本格式如下。[的两边一定要有空格,];的两边一定也要有空格,否则会有语法错误。
1 | if [ condition ]; then |
if语句的关键在于条件condition怎么写。下面给出常用的示例。
¶[和[[的区别
TODO
¶判断是否为空
一定要用双引号将变量括起来。否则,如果变量的值包含空格,则会有语法错误。
1 | if [ ! "$var" ]; then |
¶判断是否相等
在变量前加上一个附加前缀x(任意字符串均可)。否则,如果$var1为空,则会有语法错误。
1 | if [ x"$var1" = x"$var2" ]; then |
¶多条件
- 或:-o / ||
- 与:-a / &&
1 | 或逻辑用 -o |
¶数字比较
TODO
¶判断文件
| 运算符 | 描述 |
|---|---|
| -e filename | 如果文件存在则为真 |
| -d filename | 如果filename是目录则为真 |
| -f filename | 如果filename是常规文件则为真 |
| -L filename | 符号链接 |
| -c filename | 字符文件 |
| -b filename | 块文件 |
| -r filenmae | 文件可读 |
| -w filenmae | 文件可写 |
| -x filename | 文件可执行 |
¶循环语句for
for语句的基本语法如下。range变量包含一系列的值,从range中依次取出值并赋给item。可以在range的位置使用任何命令构造一系列的值。循环体可以使用continue或break关键字。
1 | for item in range |
例如,遍历当前目录的所有文件。
1 | 如果文件名包含空格,则下面的代码无法正常工作 |
¶循环语句while
基本语法如下。循环体可以使用continue或break关键字。
1 | while condition |
¶分支语句case
case语句的基本语法如下。
1 | case $var in |
¶函数
定义函数的基本语法如下。在脚本中使用funcname即可调用函数。
1 | function funcname() |
¶函数参数
与shell脚本的参数一致,具体请参考参数一节。注意$0不是函数名,依旧还是脚本的文件名。
¶函数返回值
在函数中,可以通过return关键字(提前)返回。return关键字可以携带一个参数,表示函数的返回值。通过变量$?可以获取函数的返回值。
示例代码:
1 | !/bin/bash |
示例输出:
1 | retutn with 2 |
¶函数返回字符串
return只能返回一个数字,不能返回字符串。可以在函数中使用echo输出字符串,然后将输出赋值给一个变量。如下是示例代码。注意函数的调用方式。
1 | !/bin/bash |
示例输出:
1 | [root@pkserver test]# ./function_return_string.sh |
¶eval
在命令前加上eval,会对命令扫描两遍。第一遍扫描会进行替换,第二遍执行指令。一般用于实现一遍扫描无法实现的功能。考虑如下指令,第一遍扫描会替换成echo 1,第二遍扫描执行指令,输出1。
1 | var=1 |
下面给出eval的两种应用场景。
¶变量名中包含变量
有些时候不同的变量包含了类似的数据,只是在不同的情况下选择不同的数据。如果使用if语句,if语句可能会写的很长。如果增加了一种类别,改动的地方也比较多。可以用eval解决这个问题。
假如有一个图书管理系统,现在有三种书,分别是math、computer、novel。现在要查询每种类别下有哪些书籍,可以使用eval完成。假如用户输入的是math,eval第一遍扫描会替换成echo $BOOK_math,第二遍正常执行指令。
1 | !/bin/bash |
下面是示例输出。只需要输入对应的类别,就能输出对应的书籍。如果要增加新的类别,只需要新定义一个变量即可,后面的处理代码不需要更改。
1 | 请输入类别: math |
¶向函数传递变量
通过函数参数只能传递字符串。但有些时候需要对全局变量进行操作,如果写死,则函数变得非常专一,无法通用。可以通过eval解决这个问题。
考虑下面对变量进行排序和去重的函数。将变量名作为函数参数,函数中通过变量名获取变量的值、通过变量名对变量进行赋值。
1 | !/bin/bash |
下面示例代码的输出。可以看出,函数正确实现了其功能,并且能识别出值为空的变量。
1 | [root@pkserver test]# ./eval_function.sh |
¶判断命令是否有效
1 | if ! type -t command > /dev/null; then |