循环
for/do/done
Shell脚本的for循环结构和C语言很不一样,它类似与某些编程语自的foreach循环。例如:
#! /bin/bash
for FRUIT in apple banana pear;do
echo "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 SFILENAME SFILENAME~:
done
while/do/done
while的用法和C语言类似。比如一个验证密码的脚本;
#! /bin/bash
echo "Enter password:"
read TRY
while [ "TRY" != "secret" ];do
echo "Sorry,try again"
read TRY
done
案例:命令行输入一个参数 n,计算 1+2+..+n 的值;
#/bin/bash
sum=0
i=0
while [ $i -le $1 ] #只要第i个数小于我们输入的参数,就执行循环
do
sum=$[$sum+$i]
i=$[$i+1] #i自增
done
echo "SUM=$SUM"
break/continue
break[n]可以指定跳出几层循环;continue跳过本次循环,但不会跳出循环。
即break跳出,continue跳过。
位置参数和特殊变量
有很多特殊变量是Shell自动赋值的,我们已经遇到了?和$1,其他常用的位置参数和特殊变量再这里总结一下:
$0 相当于 c 语言 main 函数的 argv[0]$1 / $2 ... 这些称为位置参数 (Positional Parameter), 相当于 c 语言 main 函数的 argv[1] 、argv[2]...$# 计算命令行参数个数 , 不包含 $0$@ 表示参数列表 " $1 " " $2 " ... 例如可以用在 for 循环中的 in 后面。$* 表示参数列表 " $1 ” " $2 ” ... 同上。$? 上一条命令的 Exit status$$ 获取当前进程号。
位置参数可以用shift命令左移。比如shift3表示原来的$4变成$1,原来的$5变成$2等等,原来的$1、$2、$3、丢弃,$0不移动。不带参数的shift命令相当于shift1。例如:
#! /bin/bashecho "The program $0 is now running"echo "The first parameter is $1 "echo "The second parameter is S2"echo "The parameter list is $@ "shiftecho "The first parameter is $1 "echo "The second parameter is S2"echo "The parameter list is $@ "
输入输出
echo
显示文本行或变量,或者把字符串输入到文件。
echo [option] string-e 解析转义字符。-n 不回车换行。默认情况 echo 回显的内容后面跟一个回车换行。echo "hello\n\n" .echo -e "hello\n\n"echo "hello"echo -n "he1lo
管道
可以通过 | 把一个命令的输出传递给另一个命令做输入
cat myfile | more1s -l | grep "myfile"
tee
tee命令把结果输出到标准输出,另一个副本输出到相应文件
例如:把ls -l显示出来后,再输入一份到ts。txt
ls -l tee ts.txt
如果需要追加的话,加入到-a
ls -l | tee -a ts.txt
文件重定向
cmd > file 把标准输出重定向到新文件中,
cmd >> file 把标准输出追加到文件cmd > file 2>&1 标准出错也重定向到 1 所指向的 file 里。cmd >> file 2>&1 追加cmd < filel > file2 < 读入 :cmd 从 file1 读入数据, > 输出 : 输出到 file2 。cmd < &fd 把文件描述符 fd 作为标准输入。 ???cmd > &fd 把文件描述符 fd 作为标准输出。 ???cmd < &- 关闭标准输入。 ???
函数
和C语言类似,Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。例如:
#! /bin/bashfun(){ echo "Function foo is called" ;}echo "-=start=-"funecho "-=end=-"
注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号}写在同
#! /bin/bashfun(){echo "Function foo is called"}echo "-=start=-"funecho "-=end=-"
在定义fun()函数时并不执行函数体中的命令,就像定义变量一样,只是给fun这个名一个定义,到后面调用fun函数的时候(注意Shell中的函数调用不写括号)才执行函数体中命令.Shell脚本中的函数必须先定义后调用,一般把函数定义语句写在脚本的前面,把函数调用和其他命令写在脚本的最后(类似C语言中的main函数,这才是整个脚本开始执行命令的地方)。
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用$0、$1、$2等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的$0、$1、$2等变量。函数中可以用return命令返回,如果return后面跟一个数字的话表示函数的Exitstatus(退出状态)。
#! /bin/bash
f2() {
echo "f2 is called."
}
f3() {
echo $0
echo $1
echo $2
echo $3
}
echo $0
echo $1
echo $2
echo $3
echo "---start----"
f3 11 22 33
echo "---end----"
下面这个脚本可以一次创建多个目录,各目录名通过命令行参数传入,脚本诸葛测试各目录是否存在,如果目录不存在,首先打印信息然后试着创建该目录。
#! /bin/bash
is_directory()
{
DIR_NAME=$1
if [ ! -d $DIR_NAME ]; then
return 1
else
return 0
fi
}
for DIR in "$@"; do
if is_directory "$DIR"
then :
else
echo "$DIR doesn't exist. creating it now...".
mkdir $DIR > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "cannot create directory $DIR"
exit 1
fi
fi
done
Shell测试
Shell提供了一些用于调试脚本的选项,如:
$ sh -x ./script.sh
#! /bin/sh -x
#! /bin/bash
if [ -z "$1" ] ; then
set -x
echo "ERROR: Insufficient Args."
exit 1
set +x
fi