1、for/do/done
Shell脚本的for
循环结构和C语言很不一样,它类似于某些编程语言的foreach
循环。例如:
#! /bin/shfor FRUIT in apple banana pear; doecho "I like $FRUIT" done
FRUIT
是一个循环变量,第一次循环$FRUIT
的取值是apple
,第二次取值是banana
,第三次取值是pear
。再比如,要将当前目录下的chap0
、chap1
、chap2
等文件名改为chap0~
、chap1~
、chap2~
等(按惯例,末尾有~字符的文件名表示临时文件),这个命令可以这样写:
$ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done
也可以这样写:
$ for FILENAME in `ls chap?`; do mv $FILENAME $FILENAME~; done2、 while/do/done
while
的用法和C语言类似。比如一个验证密码的脚本:
#! /bin/shecho "Enter password:" read TRY while [ "$TRY" != "secret" ]; doecho "Sorry, try again"read TRY done
下面的例子通过算术运算控制循环的次数:
#! /bin/shCOUNTER=1 while [ "$COUNTER" -lt 10 ]; doecho "Here we go again"COUNTER=$(($COUNTER+1)) done
Shell还有until循环,类似C语言的do...while循环。本章从略。
3、 位置参数和特殊变量有很多特殊变量是被Shell自动赋值的,我们已经遇到了$?
和$1
,现在总结一下:
常用的位置参数和特殊变量
$0 |
相当于C语言main 函数的argv[0] |
$1 、$2 ... |
这些称为位置参数(Positional Parameter),相当于C语言main 函数的argv[1] 、argv[2] ... |
$# |
相当于C语言main 函数的argc - 1 ,注意这里的# 后面不表示注释 |
$@ |
表示参数列表"$1" "$2" ... ,例如可以用在for 循环中的in 后面。 |
$? |
上一条命令的Exit Status |
$$ |
当前Shell的进程号 |
位置参数可以用shift
命令左移。比如shift 3
表示原来的$4
现在变成$1
,原来的$5
现在变成$2
等等,原来的$1
、$2
、$3
丢弃,$0
不移动。不带参数的shift
命令相当于shift 1
。例如:
#! /bin/shecho "The program $0 is now running" echo "The first parameter is $1" echo "The second parameter is $2" echo "The parameter list is $@" shift echo "The first parameter is $1" echo "The second parameter is $2" echo "The parameter list is $@"4、函数
和C语言类似,Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。例如:
#! /bin/shfoo(){ echo "Function foo is called";} echo "-=start=-" foo echo "-=end=-"
注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号}
写在同一行,命令末尾必须有;号。
在定义foo()
函数时并不执行函数体中的命令,就像定义变量一样,只是给foo
这个名字一个定义,到后面调用foo
函数的时候(注意Shell中的函数调用不写括号)才执行函数体中的命令。Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的main
函数,这才是整个脚本实际开始执行命令的地方)。
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0
、$1
、$2
等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的$0
、$1
、$2
等变量。函数中可以用return
命令返回,如果return
后面跟一个数字则表示函数的Exit Status。
下面这个脚本可以一次创建多个目录,各目录名通过命令行参数传入,脚本逐个测试各目录是否存在,如果目录不存在,首先打印信息然后试着创建该目录。
#! /bin/shis_directory() {DIR_NAME=$1if [ ! -d $DIR_NAME ]; thenreturn 1elsereturn 0fi }for DIR in "$@"; doif is_directory "$DIR"then :elseecho "$DIR doesn't exist. Creating it now..."mkdir $DIR > /dev/null 2>&1if [ $? -ne 0 ]; thenecho "Cannot create directory $DIR"exit 1fifi done
注意is_directory()
返回0表示真返回1表示假。