shell 脚本的使用该熟练起来了,你说呢?(篇四)
继续前一篇的文章:
文章里面测试的命令脚本文件,大家关注我公众号后,可以私信我领取文件。
作者:良知犹存
转载授权以及围观:欢迎添加微信公众号:羽林君
Shell test 命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的试。
数值测试
参数
说明
实例
输出结果:
代码中的 [] 执行基本的算数运算,如:
结果为:
字符串测试
参数
说明
实例
输出结果:
文件测试
参数
说明
实例:
输出结果:
另外,Shell 还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。
实例:
输出结果:
Shell 流程控制
和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法):实例
在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else。
**if **
if 语句语法格式:
写成一行(适用于终端命令提示符):
末尾的fi就是if倒过来拼写,后面还会遇到类似的。
if else
if else 语法格式:
if else-if else
if else-if else 语法格式:
以下实例判断两个变量是否相等:
实例
输出结果:
if else 语句经常与 test 命令结合使用,如下所示:
实例
输出结果:
for 循环
与其他编程语言类似,Shell支持for循环。
for循环一般格式为:
写成一行:
当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。in列表是可选的,如果不用它,for循环使用命令行的位置参数。
例如,顺序输出当前列表中的数字:
实例
输出结果:
顺序输出字符串中的字符:
输出结果:
shell 中的 for 循环不仅可以用文章所述的方法。
对于习惯其他语言 for 循环的朋友来说可能有点别扭。
如上所示,这里的 for 循环与 C 中的相似,但并不完全相同。
通常情况下 shell 变量调用需要加 $,但是 for 的 (()) 中不需要,下面来看一个例子:
执行结果:
与 C 中相似,赋值和下一步执行可以放到代码之前循环语句之中执行,这里要注意一点:如果要在循环体中进行 for 中的 next 操作,记得变量要加 $,不然程序会变成死循环。
while 语句
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:
以下是一个基本的while循环,测试条件是:如果int小于等于5,那么条件返回真。int从0开始,每次循环处理时,int加1。运行上述脚本,返回数字1到5,然后终止。
实例
运行脚本,输出:
以上实例使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上
来表示变量,具体可查阅:let 命令。(let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。)
while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按结束循环。
实例
运行脚本,输出类似下面:
无限循环
无限循环语法格式:
或者
或者
until 循环
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
until 语法格式:
condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
以下实例我们使用 until 命令来输出 0 ~ 9 的数字:
实例
运行结果:
输出结果为:
case
Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:
case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
下面的脚本提示输入1到4,与每一种模式进行匹配:
实例
输入不同的内容,会有不同的结果,例如输入了3:
跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。
break命令
break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
实例
执行以上代码,输出结果为:
continue
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
对上面的例子进行修改:
实例
运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo "游戏结束" 永远不会被执行。
case ... esac
case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。
case ... esac 语法格式如下:
case 后为取值,值可以为变量或常数。
值后为关键字 in,接下来是匹配的各种模式,每一模式最后必须以右括号结束,模式支持正则表达式。
实例
输出结果为:
Shell 函数
linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。
shell中函数的定义格式如下:
说明:
1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255
下面的例子定义了一个函数并进行调用:
输出结果:
下面定义一个带有return语句的函数:
输出类似下面:
函数返回值在调用该函数后通过 $? 来获得。
注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
函数参数
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过
n 的形式来获取参数的值,例如,1表示第一个参数,$2表示第二个参数...
带参数的函数示例:
输出结果:
注意,
10 不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用${n}来获取参数。
另外,还有几个特殊字符用来处理参数:
参数处理
说明
?** 仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 **? 获得。
测试代码:
输出结果:
调用 demoFun2 后,函数最后一条命令 expr 1 + 1 得到的返回值($?值)为 0,意思是这个命令没有出错。所有的命令的返回值仅表示其是否出错,而不会有其他有含义的结果。
第二次调用 demoFun1 后,没有立即查看
? 的值,而是先插入了一条别的 echo 命令,最后再查看 ? 的值得到的是 0,也就是上一条 echo 命令的结果,而 demoFun1 的返回值被覆盖了。
下面这个测试,连续使用两次 echo $?,得到的结果不同,更为直观:
输出结果:
函数与命令的执行结果可以作为条件语句使用。要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false。
请参见下例:
其执行结果如下:
grep 是从给定字符串中寻找匹配内容的命令。首先看出如果找到了匹配的内容,会打印匹配部分且得到的返回值
? 为 0,如果找不到,则返回值 ? 为 1。
接下来分别将这两次执行的 grep 命令当作条件语句交给 if 判断,得出返回值
? 为 0,即执行成功时,条件语句为 true,当返回值 ? 为 1,即执行失败时,条件语句为 false。
之后再用函数的 return 值作为测试,其中 demoFun1 返回值为 0,demoFun2 返回值选择了任意一个和 0 不同的整数,这里为 12。
将函数作为条件语句交给 if 判断,得出返回值为 0 时,依然为 true,而返回值只要不是 0,条件语句都判断为 false。
Shell 输入/输出重定向
大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。
重定向命令列表如下:
命令
说明
需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
输出重定向
重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示:
上面这个命令执行command1然后将输出的内容存入file1。
注意任何file1内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用>>操作符。
实例
执行下面的 who 命令,它将命令的完整的输出重定向在用户文件中(users):
执行后,并没有在终端输出信息,这是因为输出已被从默认的标准输出设备(终端)重定向到指定的文件。
你可以使用 cat 命令查看文件内容:
输出重定向会覆盖文件内容,请看下面的例子:
如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如:
输入重定向
和输出重定向一样,Unix 命令也可以从文件获取输入,语法为:
这样,本来需要从键盘获取输入的命令会转移到文件读取内容。
注意:输出重定向是大于号(>),输入重定向是小于号(<)。
实例
接着以上实例,我们需要统计 users 文件的行数,执行以下命令:
也可以将输入重定向到 users 文件:
注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。
同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中。
重定向深入讲解
一般情况下,每个 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。
如果希望 stderr 重定向到 file,可以这样写:
如果希望 stderr 追加到 file 文件末尾,可以这样写:
2 表示标准错误文件(stderr)。
如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
如果希望对 stdin 和 stdout 都重定向,可以这样写:
command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。
Here Document
Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。
它的基本的形式如下:
它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。
注意:
结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
开始的delimiter前后的空格会被忽略掉。
** **
** **
实例
在命令行中通过 wc -l 命令计算 Here Document 的行数:
我们也可以将 Here Document 用在脚本中,例如:
执行以上脚本,输出结果:
/dev/null 文件
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
如果希望屏蔽 stdout 和 stderr,可以这样写:
注意:0 是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
这里的 2 和 > 之间不可以有空格,2> 是一体的时候才表示错误输出。
这里的**&**没有固定的意思
放在**>后面的&,表示重定向的目标不是一个文件**,而是一个文件描述符,内置的文件描述符如下
换言之 2>1 代表将stderr重定向到当前路径下文件名为1的regular file中,而2>&1代表将stderr重定向到文件描述符为1的文件(即**/dev/stdout**)中,这个文件就是stdout在file system中的映射
而**&>file是一种特殊的用法,也可以写成>&file**,二者的意思完全相同,都等价于
此处**&>或者>&**视作整体,分开没有单独的含义
顺序问题:
这个是从左到右有顺序的
第一种
先将要输出到stdout的内容重定向到文件,此时文件list就是这个程序的stdout,再将stderr重定向到stdout,也就是文件list
第二种
先将要输出到stderr的内容重定向到stdout,此时会产生一个stdout的拷贝,作为程序的stderr,而程序原本要输出到stdout的内容,依然是对接在stdout原身上的,因此第二步重定向stdout,对stdout的拷贝不产生任何影响
对于上面 '2>&1',举个例子,比如说:
从左往右执行,执行到 >list,此时的 stdout 为 list;而执行到 2>&1,表示 stderr 重定向到 stdout,这里也就是 list 文件。
因为 [ find /etc -names "*.txt" ] 这条命令是错误的( -names 应该是 -name)。
本来要输出到终端屏幕的错误信息:
被重定向到了 stdout 也就是 list 文件中,所以屏幕不会出现错误信息,而是打印到了 list 文件中。
cat list 可以查看到 find: unknown predicate `-names' 就在里面。
直接在 FreeBSD 或者 csh 中使用 command > file 2>&1 时候会得到这个错误:Ambiguous output redirect。
出错的原因在于 FreeBSD 默认使用 csh,在 csh 中如果想把标准输出和错误输出同时重定向到一个文件,需要用下面命令 command >& file。
这就是我分享的shell脚本,其中参考了很多人的文章,如果大家有什么更好的思路,也欢迎分享交流哈。
**—*END*—
【1】 C++的智能指针你了解吗?
【3】CPU中的程序是怎么运行起来的 必读
【5】阶段性文章总结分析
本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。
更多分享,扫码关注我
参考链接:
https://www.runoob.com/linux/linux-shell-variable.html
版权声明: 本文为 InfoQ 作者【良知犹存】的原创文章。
原文链接:【http://xie.infoq.cn/article/ba8f92b30d0920d8364c232fc】。文章转载请联系作者。
评论