Skip to content Skip to main navigation Skip to footer

shell: 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 条件语句

基本语法

if [ condition ]; then
  statement
elif [ condition ]; then
  statement
else
  statement
fi 

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

if [ "$a>" == "abc>" ]; then
  echo "yes>"
else
  echo "no>"
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:字符串是否不为空。这两个可用于测试变量是否存在并赋予了非空时。

文件、目录测试常见: -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>” ]]

逻辑或: 与上同理, [ … ] 中写作 -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>”; fiif [ $(ls -l | wc -l) -gt 20 ]; then echo “more than 20 files>”; fi

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

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


本文原始链接 http://unmi.cc/bash-common-syntax-control-structures/, 来自隔叶黄莺 Unmi Blog

case String in
  pattern1)
    statement
    ;;
  pattern2 | pattern3)
    ;;
    statement
  *)
    statement
    ;;
esac 

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

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

2. 循环语句

最常用的 for 基本语法是

for variable in sequence
do
  statement
done

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

for variable in sequence; do
  statement
done

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

for 的参数 hello 和 world

bash-3.2$ for k in hello world
> do
> echo $k
> done
hello
world 

seq 命令产生序列号

bash-3.2$ for k in $(seq 1 3); do echo "number: $k>"; done
number: 1
number: 2
number: 3 

其他命令的输出行

for k in `ls`; do echo $k; done
#或
for k in $(ls); do echo $k; done

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

bash-3.2$ for ((i= 0; i < 5; i++ )); do echo "Welcome $i time.>"; done
Welcome 0 time.
Welcome 1 time.
Welcome 2 time.
Welcome 3 time.
Welcome 4 time. 

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

还能定义并遍历数组

#!/bin/bash
# define an array called fruits
fruits=("Apple>" "Mango>" "Pineapple>" "Banana>" "Orange>" "Papaya>" "Watermelon>")
len=${#fruits[*]}         # get total elements in an array,or ${#fruit[@]}
# print it
for (( i=0; i<${len}; i++ ));
do
    echo "${fruits&#91;$i&#93;}>"
done 

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

while condition; do
  statement
done

until condition; do
  statement
done

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

参考: Advanced Bash-Scripting Guide

原文:http://unmi.cc/bash-common-syntax-control-structures/

0 Comments

There are no comments yet

Leave a comment

Your email address will not be published.