你可以在Shell脚本程序内部执行两类命令:内部命令和外部命令。内部命令是在Shell内部实现的,不能作为外部程序被调用,但相比外部命令而言内部命令执行更有效率,不过本文中并不区分内部还是外部命令。
一、break命令
这个命令可以用于跳出for、while或者until循环。
不过与C语言不同的是可以为break命令提供一个额外的数值参数来表明所要跳出的循环层数,但并不建议这么做,因为这会大大降低程序的可读性。
默认情况下,break只跳出一层循环。
二、:命令
冒号:命令是一个空命令。它偶尔会被用于简化条件逻辑,相当于true的一个别名。由于它是内置命令,所以它运行得比true快,但它的输出可读性比较差。
你可能会看到将它用作while循环的条件,while :实现了一个无线循环,代替了更常见的while true。
:结构也会被用在变量的条件设置中,例如:
: ${var := value}
如果没有:,shell将试图把$var当作一条命令来处理。
三、continue命令
非常类似于C语言中的同名语句,这个命令使for、while或until循环跳到下一次循环继续执行,循环变量取循环列表中的下一个值。
continue可以带一个可选的参数以表示希望继续执行的循环嵌套层数,也就是说你可以部分的跳出嵌套循环。这个参数很少用,因为它会致使脚本程序极难理解,比如:
for x in 1 2 3
do
echo before $x
continue 1
echo after $x
done
上面程序输出:
before 1
before 2
before 3
四、.命令
点.命令用来执行当前shell中的命令:
. ./shell_script
通常,当一个脚本执行一条外部命令或脚本程序时,会创建一个新的环境(一个子shell),命令将在这个新环境中执行,在命令执行完毕后,这个环境被丢弃,只留下退出码返回给父shell。而外部的source命令和点命令(这两个命令差不多是同义词)在执行某个脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。通常被调用命令对环境变量做出的任何改变都会丢失,而点命令允许执行的命令改变当前环境。当你要把一个脚本当做“包裹器”来为后续执行的一些命令设置环境时,这个命令通常就很有用。
在shell脚本程序中,点命令的作用有点类似于C和C++语言里的#include指令,尽管它并没有从字面意义上包含脚本,但它的确是在当前上下文中执行命令,所以你可以使用它将变量和函数定义结合进一个脚本程序。
五、echo命令
echo命令用来输出结尾带有换行符的字符串,当然也可以如下来去掉换行符:
echo -n "string to output"
六、eval命令
eval命令允许你对参数进行求值,举例说明如下:
foo = 10
x = foo
y = '$'$x
echo $y
执行上面脚本输出"$foo"。
foo = 10
x = foo
eval y='$'$x
echo $y
执行上面脚本输出10,因此,eval命令有点像一个额外的$,它给出一个变量的值的值。
eval命令十分有用,它允许代码被随时生成和运行,虽然这会增加脚本调试的复杂度,但它可以让你完成使用其它方法难以或者根本无法完成的事情。
七、exec命令
exec命令有两种不同的用法。它的典型用法是将当前shell替换为一个不同的程序,比如:
exec wall "Thanks for all the fish"
脚本中的这个命令会用wall命令替换当前的shell,脚本程序中exec命令后面的代码都不会执行,因为执行这个脚本的shell已经不存在了。
exec的第二种用法是修改当前文件描述符:
exec 3< afile
这使得文件描述符3被打开以便从文件afile中读取数据,这种用法非常少见。
八、exit n命令
exit命令使脚本程序以退出码n结束运行,如果你在任何一个交互式shell的命令提示符中使用这个命令,它都会让你退出系统。如果你允许自己的脚本程序在退出时不指定一个退出状态,那么该脚本中最后一条被执行命令的状态将被用作返回值。
在shell脚本编程中,退出码0表示成功,退出码1~125是脚本程序使用的错误码,其余数字具有保留意义,比如:126表示文件不可执行、127表示命令未找到、128及以上表示出现一个信号。
九、export命令
export命令将作为它参数的变量导出到子shell中,并使之在子shell中有效。默认情况下,在一个shell中被创建的变量在这个shell调用的下级(子)shell中是不可用的。export命令把自己的参数创建为一个环境变量,而这个环境变量可以被其它脚本和当前程序调用的程序看见,即被导出的变量构成从该shell衍生的任何子进程的环境变量。举例说明如下:
(1)脚本程序export2:
#!/bin/sh
echo "$foo"
echo "$bar"
(2)脚本程序export1,这个脚本调用了export2:
#!/bin/sh
foo = "The first meta-syntactic varible"
export bar = "The second meta-syntactic variable"
export2
运行脚本export1:
$export1
The second meta-syntactic variable
第一个空行的出现是因为变量foo在export2中不可用,所以$foo被赋值为空,echo一个空变量将输出一个空行。
当变量被一个shell导出后,它就可以被该shell调用的任何脚本使用,也可以被后续调用的任何shell使用。如果脚本export2调用了另一个脚本,bar的值对新脚本来说仍然有效。
set -a或者set -allexport命令将导出它之后声明的所有变量。
十、expr命令
expr命令将它的参数当作一个表达式求值,它的最常见用法就是进行如下形式的简单数学运算:
x = `expr $x + 1`
反引号字符使x取值为命令expr $x + 1的执行结果。我们也可以用语法$()替换反引号:
x = $(expr $x + 1)
expr命令功能很强大,可以完成许多表达式求值计算:
expr1 | expr2:如果expr1非零,则等于expr1,否则等于expr2
expr1 & expr2:只要有一个表达式为零,则等于零,否则等于expr1
expr1 = expr2:等于
expr1 > expr2:大于
expr1 >= expr2:大于等于
expr1 < expr2:小于
expr1 <= expr2:小于等于
expr1 != expr2:不等于
expr1 + expr2:加法
expr1 - expr2:减法
expr1 * expr2:乘法
expr1 / expr2:整除
expr1 % expr2:取余
在最新的脚本程序中,expr命令通常被替换为更有效的$((...))语法。
十一、printf命令
printf命令用来代替echo命令以产生格式化的输出,其语法格式如下:
printf "format string" parameter1 parameter2 ...
格式字符串与C/C++相似,但不支持浮点数,因为shell中所有算术运算都是按照整数进行计算的。举例说明如下:
$printf "%s\n" hello
hello
$printf "%s %d\t%s" "Hi There" 15 people
Hi There 15 people
注意:必须使用双引号括住Hi There字符串,使之成为一个单独的参数。
十二、return命令
return命令的作用是使函数返回,其有一个数值参数,这个参数在调用函数的脚本程序里被看做该函数的返回值,如果没有指定参数,return命令默认返回最有一条命令的退出码。
十三、set命令
set命令的作用是为shell设置参数变量。许多命令的输出结果是以空格分隔的值,如果需要使用输出结果中的某个域,这个命令就非常有用。
比如:我们想在shell脚本中使用当前月份的名字,那么可以使用set命令和$(...)结构的组合来执行date命令以提取月份字符串。
#!/bin/sh
echo the date is $(date)
set $(date)
echo The month is $2
exit 0
这个程序把date命令的输出设置为参数列表,然后通过位置参数$2获取月份。
十四、shift命令
shift命令把所有参数变量左移一个位置,使$2变成$1,$3变成$2,依此类推。原来$1的值将被丢弃,而$0仍将保持不变。如果调用shift命令时指定了一个数值参数,则表示所有的参数将左移指定的次数。$*、$@和$#等其它变量也将根据参数变量的新安排做相应的变动。在扫描处理脚本程序的参数时经常要用到shift命令,假如你的脚本程序需要10个或以上的参数,你就需要用shift命令访问第10个及其后面的参数,下面举例说明如何依次扫描所有的位置参数:
#!/bin/sh
while [ "$1" != "" ]; do
echo "$1"
shift
done
exit 0
十五、trap命令
trap命令用于指定在接收到信号后将要采取的行动,trap命令的一种常见用途是在脚本程序被中断时完成清理工作。历史上,shell总是用数字来代表信号,而新的脚本程序应该使用信号的名字,它们保存在signal.h头文件中,在使用信号名时需要省略SIG前缀,你可以在命令提示符下输入命令trap -l来查看信号编号及其关联的名称。
trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名:
trap command signal
需要注意的是:脚本程序通常是以从上到下的顺序解释执行的,所以必须在你想保护的那部分代码以前指定trap命令。
如果要重置某个信号的处理条件到其默认值,只需简单地将command设置为-。如果要忽略某个信号,就把command设置为空字符串‘’。一个不带参数的trap命令将列出当前设置的信号及其行动的清单。
能够被捕获的比较重要的信号如下,括号中的数字表示信号编号,更多细节请man 7 signal查看:
HUP(1):挂起,通常因终端掉线或用户退出而引发。
INT(2):中断,通常因按下Ctrl+C组合键而引发。
QUIT(3) :退出,通常因按下Ctrl+\组合键而引发。
ABRT(6):中止,通常因某些严重的执行错误而引发。
ALRM(14):报警,通常用来处理超时。
TERM(15):终止,通常在系统关机时发送。
下面的脚本演示了一些简单地信号处理方法:
#!/bin/sh
trap 'rm -f /tmp/my_temp_file_$$' INT
echo createing file /tmp/my_tmp_file_$$
echo "press interrupt CTRL+C to interrupt ..."
while [ -f /tmp/my_tmp_file_$$ ] ; do
echo File exists
sleep 1
done
echo The file no longer exists
trap INT
echo createing file /tmp/my_tmp_file_$$
echo "press interrupt CTRL+C to interrupt ..."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo we never get here
exits
执行上面脚本,按下CTRL+C,将输出如下:
create file /tmp/my_tmp_file141
pree interrupt CTRL+C to interrupt ...
File exists
File exists
The file no longer exists
create file /tmp/my_tmp_file_141
press interrupt CTRL+C to interrupt ...
File exists
File exists
File exists
在这个脚本程序中,先用trap命令安排它在出现一个INT信号时执行rm -f /tmp/my_tmp_file_$$命令删除临时文件。脚本程序然后进入一个while循环,只要临时文件存在,循环就一直持续下去。当用户按下CTRL+C时,就会删除临时文件,随之第一个while循环将正常退出。接下来,脚本程序再次调用trap命令用以指定当出现一个INT信号时不执行任何命令。脚本程序然后重新创建临时文件并进入第二个while循环。当用户再次按下CTRL+C时,没有语句被指定执行,所以才有默认处理方式,即立即终止脚本程序,故永远不会执行最后的echo和exit语句。
十六、unset命令
unset命令的作用是从环境变量中删除变量或函数。这个命令不能删除shell本身定义的只读变量(如IFS)。下面脚本第一次输出字符串“Hello World”,但第二次只输出一个换行符:
#!/bin/sh
foo = "Hello World"
echo $foo
unset $foo
echo $foo
使用foo=语句产生的效果与unset命令差不多但并不等同。foo=将变量foo设置为空,但变量foo仍然存在,而使用unset foo语句的效果是把变量foo从环境中删除。
阅读(3237) | 评论(3) | 转发(1) |