Commands(2)
export
export命令能够将变量命名为在子shell中的参数变量。默认状况下,在一个shell生成的变量是不能被此shell的子shell所调用的。而export命令可以通过它的参数生成一个环境变量,这个参数可以被在当前程序下所调用的其他脚本和程序所发现。更专业些来说,就是说来自于该shell的子进程中的环境变量都是由此shell所导出的变量构成。下面是连个脚本export1和export2的示例:
首先,export2#!/bin/sh
echo "$foo"
echo "$bar"
#!/bin/sh
foo="The first meta-syntactic variable"
export bar="The second meta-syntactic variable"
export2
$ ./export1
结果显示:
The second meta-syntactic variable
一旦一个变量被shell所导出,那么由这个shell所派生的或者在该shell中依次调用的脚本中就都是可见的。如果脚本export2调用了另外一个的脚本,那么对于另外一个脚本而言,bar这个变量的值依旧是可见的。
注:我们可以通过set -a 或 set -allexport来导出所有在其后的变量。
expr
expr命令可以给它的参数像一个表达式一样赋值。它在最简单的算术运算上的普遍用法如下面的形式所示:
x=`expr $x + 1`
``(backtick)反引号字符作用是令x得到expr $x + 1的结果,你也可以用$( )来代替反引号,比如:x=(expr $x + 1)
expr很强大,它可以执行一些表达式赋值操作。以下是一些主要的表达式赋值操作:
Expression Evaluation | Description |
expr1 | expr2 | expr1非零时返回expr1,否则返回expr2 |
expr1 & expr2 | 表达式中任意一个为0则返回0,否则返回expr1 |
expr1 = expr2 | 相等 |
expr1 > expr2 | 大于 |
expr1 >= expr2 | 大于等于 |
expr1 < expr2 | 小于 |
expr1 <= expr2 | 小于等于 |
expr1 != expr2 | 不等于 |
expr1 + expr2 | 相加 |
expr1 - expr2 | 相减 |
expr1 * expr2 | 相乘 |
expr1 / expr2 | 整数相除 |
expr1 % expr2 | 整数求模 |
printf
printf命令只能在比较近的shell版本里面运行。X/Open建议我们优先使用printf来生成格式化的输出,而不是echo,尽管好像只有一小部分人采纳了该建议。
printf的语法规则:printf "format string" parameter1 parameter2 ...
格式化字符串(format string)同C或C++中使用相类似,只是有一些限制。最主要的区别就是shell不支持精度小数点,所有的算术运算在shell中都是以整数来运算。格式化字符串由字母、转义序列以及转义字符所组成,除了%和\外,所有的字符都可以精确地输出。
下面就是支持的转义序列:
Escape Sequence | Description |
\" | 双引号 |
\\ | 反斜杠 |
\a | 警报(发出警铃声或蜂鸣声) |
\b | 退格 |
\f | 形成输入字符 |
\n | 新行字符 |
\r | 回车 |
\t | Tab字符 |
\v | 垂直Tab |
\ooo | 由八进制表示的单个字符 |
\xHH | 由十六进制表示的单个字符 |
转义字符是相当复杂的,因此我们只在此列出一些普遍的用法。转移字符符由一个%字符跟一个转义字符所组成。下面是主要的转义字符:
Conversion Specifier | Description |
D | 输出一个十进制数值 |
C | 输出一个字符 |
S | 输出一个字符串 |
% | 输出%字符 |
格式化字符串被用来解释剩余的参数和输出结果,如下例所示:
$ printf "%s\n" hellohello
$ printf "%s %d\t%s" "Hi There" 15 people
Hi There 15 people
return
return命令是用来促使函数的返回,这一点在以前所看过的函数那里就提及过了。return在脚本调用函数之后会带着一个单一有效的数值参数返回,如果没有指定返回参数,return默认将返回最后运行的命令的退出状态。
set
set命令是用来给shell设定参数变量的值,这对于输出由空格来隔离的命令使用域来说,是一种有效的方法。假设你想要在一个shell脚本中使用当前月份的名称,系统为我们提供了date命令,在其输出中,月份只是其中的一个字符串,因此我们需要把它从中分离出来。这时,我们就需要通过set命令和$(...)组合运行date命令并返回我们所要的结果。在date命令的输出中,月份所占的字符串是它的第二个参数。示例如下:
#!/bin/sh
echo the date is $(date)
echo $(date)
echo The month is $2
exit 0
上面的程序设定date命令输出的参数列,之后根据位置参数$2得到月份。
注意:我们使用date命令的一个小小示例来展示如何提取位置参数。由于date命令对本地系统语言的敏感,事实上我们在提取月份的名称时,会使用date +%B来获得。date命令用很多的格式化参数选项,要了解更多请翻阅相关的手册。
我们也可以使用set命令通过shell的参数来控制该shell所运行的方式。最普遍的用法是:set -x,它可以显现出当前运行的命令的踪迹。我们将在以后有关debugging的章节再深入讨论set以及set的选项。
shift
shift命令用来将所有的参数变量一个一个地向下移动,也就是$2变成了$1,$3变成了$2,一直到最末位。当然,前面的$1将被丢弃,不过$0保持不变。如果调用shift命令时指定了一个数值参数,那么参数就移动对应的空格。至于其他的变量,比如:$*,$@以及$#同样会被参数变量新的排列所改变。
shift经常用来扫描一个脚本中所包含的参数,如果你的脚本需要10个或更多的参数,你可以使用shift来访问第十个以及其后的。例如,你可以像这样来扫描所有的位置参数:
#!/bin/sh
while [ "$1" != "" ]; do
echo "$1"
done
exit 0
trap
trap命令被用来指定在收到信号时所要进行的动作,一种普遍的用法是在脚本被中断时对脚本所做的处理工作。由于历史原因,shell总是用数字来标示信号,不过在新的脚本里,可以通过#include文件signal.h的方式,在省略SIG的前缀的情况下以名字来标示。如果想要看信号的数字以及对应的名字,我们只需在命令提示符下键入trap -l即可。
trap可以通过在其后紧跟信号名称的方式来捕获信号:trap command signal记住脚本正常中断都是从上到下进行,因此我们必须在想要保护的脚本代码片段前指定trap命令。
要重新设定一个trap的条件为默认条件,只需简单指定命令为-。而要忽略一个信号,则需要设定命令为空串''。一个不带参数的trap命令只输出当前的动作列表。
下表将列出一些可以被捕获的比较重要的X/Open标准信号,它们都和圆括号中的传统信号数字在一起。
Signal | Decription |
HUP(1) | 挂起;通常当一个终端离线或用户退出是发送 |
INT(2) | 中断;通常在按下Ctrl+C时发送 |
QUIT(3) | 退出;通常在按下Ctrl+\时发送 |
ABRT(6) | 中止;通常在一些严重的运行错误时发送 |
ALRM(4) | 警报;通常用于处理超时 |
TERM(15) | 终止;通常当系统关闭时发送 |
下面的脚本示范了一些简单的信号处理:
#!/bin/sh
trap 'rm -f /tmp/my_tmp_file_$$' INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (Crtl+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 creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (Crtl+C) to interrupt ....."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo we never get here
exit 0
creating file /tmp/my_tmp_file_141
press interrupt (Ctrl+C) to interrupt .....
File exists
File exists
File exists
File exists
The file no longer exists
creating file /tmp/my_tmp_file_141
press interrupt (Ctrl+C) to interrupt .....
File exists
File exists
File exists
File exists
unset
unset命令的功能是从环境中删除变量或函数,不过它不能删除shell自己所定义的只读变量,比如IFS。另外,unset命令不是经常被使用。
下面的脚本会先输出Hello World,之后输出一个新行,代码如下:#!/bin/sh
foo="Hello World"
echo $foo
unset foo
echo $foo