Bash 的常用语法,控制结构

最近玩弄 Jenkins 较多,构建服务器基本是 Mac OS 和 Linux,虽说有许多现成插件可用,但不敢不说 Execute Shell 这个东西都是即开即用,方便而灵活的。因此不断的要和 Shell 打交道,真正通用的的 Shell 自然是 Bash,在 Mac OS 下可发现自带了 zsh, ksh 和 tcsh,考虑到 Linux 还是 Bash 吧。

本人工作时用的是 Fish Shell,目前相当的脚本语言都可用来写 Shell 脚本,如 PHP, Ruby, Python, Perl,NodeJs 等,只是 Bash 的地位总难被替代,借句话说 Bash 的是拿来 “用” 的,而像 Ruby, Python 等做 Shell 是拿来 “编” 的,再就是 Bash 与 Linux 命令的亲缘性更强。

我也只会在实在用 Bash 太难于表达的时候才用其他脚本语言,如处理日期的运算,因 Mac OS 的 date 和 Linux 的 date 命令差异较大,不得已会选择有较强类型的 Ruby 等。

既然 Bash 要作为一个日常语言,那不妨作个备忘录,记录下那些常用的语法,控制结构。

1. if 条件语句

基本语法

elif 和 else 是可选部分,结尾要用 if 反着写的 fi,简单例子

写上面的脚本一定要与我们的高级编程语方区分开来理解,Bash 只认命令,所有上面

1. [ 前后要有空格, == 前后要有空格, ] 前要有空格,if 是个 shell 命令,所以后面的每一部分都是作为它的一个个参数
2. then 之前的分号,因为本质上 if 和 then 是两个命令,所以需要用分别隔开,我们也可以 then 另起一行,则分号可省略。
3. if 后面也可以用 [[ condition ]] 或 (( condition )),(( ... )) 在循环语句中会碰到。

下面就是关于条件测试

全面的说明在这里 http://www.tldp.org/LDP/abs/html/refcards.html#AEN22473

下面列此常用的:
等于: -eq(equal) ,== 或 =
大于:-gt(greater than), 字符串比较用  \>,如果是 [[ ... ]],\> 则要写成 >,像 if [[ "b" > "a" ]]
大于等于:-ge(greater equal),写在 (( ... )) 中可写成  >=,如  if (( $a >= 3 ))
小于:-lt(less than) 或 \< 用于比较字符, 在 [[ ... ]] 中\< 要写成  <
小于等于:-le(less equal) , (( ... )) 中用 <=, 如 if (( $a <= 3 ))
不等于:-ne(not equal) 或 !=

有时得注意引号的使用,能避免空白的引入,假如写成

if [ $a -gt 7 ], 当 $a 是空白的时候,就被解析成  if [ -gt 7 ] 执行时就会报错,这时为保险需写成  if [ "$a" -gt 7 ] 这时即时  $ 没值也是 if [ "" -gt 7 ],语法上不会有问题

另外需说一个模式匹配符 "=~",判断左边的字符串能否被右边的模式所匹配,用于[[ expression ]]

例如:if [[ abc123 =~ [a-z]{3}[0-9]{3} ]], 字符串和模式都不需要引号括起来,正则表达也是比较有限的支持,这里不能用 \d 替代 [0-9]

一些单目测试:

-z:字符串是否为空,  -n:字符串是否不为空。这两个可用于测试变量是否存在并赋予了非空时。
其实像多数编程语言一样空为否,如 if [ "" ], 或 $a 不存在时 if [ "$a" ] 都是 false

文件、目录测试常见: -e 文件是否存在    -d:测试是否目录, -f:测试是否普通文件,还有诸如是否块文件,socket 文件,是否有读、写、执行的权限,文件大小是否为零等等。详见 http://www.tldp.org/LDP/abs/html/refcards.html#AEN22473

组合条件测试:

逻辑与: [ ... ] 写成 -a (and), [[ ... ]] 中写成  &&, if  [ "a" = "a" -a "b" = "b" ], if  [[ "a" = "a" && "b" = "b" ]],也能这样写 if [ "a" = "a" ] && [ "b" = "b" ]
逻辑或: 与上同理, [ ... ] 中写作 -o (or), [[ ... ]] 中写成  ||
逻辑非: 写成  if [ ! "a" = "a" ] 这个相当于 if [ "a" != "a" ] 了,但 ! 可放到任何地方 if [ ! "$b" -gt 7" ], if [ ! -z "$abc" ]

条件语句的内容大概就是这些了,至于比较内容的获得就是随你意了,可以是脚本变量,环境变量,参数,或执行 shell 的返回结果,如

if [ ls -l | wc -l -gt 20 ]; then echo "more than 20 files"; fi
if [ $(ls -l | wc -l) -gt 20 ]; then echo "more than 20 files"; fi

backtick 和 $() 都可以收集执行命令后的返回值。

另外 Bash 还支持 case 语句,基本语法是

要说这个语法还有些怪异,模式后只用单右括号,;; 相当于是 break,  结尾是 case 反着写的的 esac

不举例子,看何时真正用上再细究。

2. 循环语句

最常用的 for 基本语法是

也可以像前面 if 那样的写法,把 do 提到上一行去

这是代码风格问题,for 和 do 两个命令写成一行就需要用分号隔开。来看可以怎么产生需要的序列

for 的参数 hello 和 world

seq 命令产生序列号

其他命令的输出行

那么这里不得不提到 C-Style 的循环

我们也要注意到这里 for 后面 ((...)) 中的写法也不像 [ ... ] 里那么严格,(( 后可以不用空格,等号前后可以不用空格,就是按照 C 的写法,只是必须双重括号。

还能定义并遍历数组

另外 Bash 还当仁不让的支持  while, until 这两种循环,不细说他们了,基本语法是

condition 部分的语法可参考 if 条件语句。

参考:Advanced Bash-Scripting Guide

本文链接 https://yanbin.blog/bash-common-syntax-control-structures/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments