shell脚本编程之一

    ls
        打印在当前目录中的文件的名字。
    ls >file
        把来自 ls 的输出放置到 file 中。
    ls | wc -l
        打印在当前目录中文件的数目。
    ls | grep old
        打印包含字符串 old 的那些文件名字。
    ls | grep old | wc -l
        打印名字中包含字符串 old 的那些文件的数目。
    cc pgm.c &
        在后台运行 cc。

可以用 shell 读取和执行包含在文件中的命令。例如,

sh file [ args ... ]

调用 shell 来从 file 读取命令。这样的文件叫做命令过程或 shell 过程。实际参数可以提供给调用并在 file 中用位置参数 $1、$2、....来引用。例如,如果文件 wg 包含
who | grep $1

sh wg fred
等价于
who | grep fred

UNIX 文件有三个独立的属性,读、写和执行。可以使用 UNIX 命令 chmod (1)来使文件可执行。例如,

chmod +x wg

将确保文件 wg 有可执行状态。此后,命令

wg fred
等同于
sh wg fred

同为位置参数提供名字一样,在调用中位置参数的数目可获得为 $#。被执行的文件的名字可获得为 $0。一个特殊的 shell 参数是 $* 被用来替换除了 $0 之外的所有位置参数。它的典型用途是提供一些缺省实际参数。


控制流for
tel 的文本是

for i
do grep $i /usr/lib/telnos; done
命令
tel fred

打印在 /usr/lib/telnos 中包含 fred 的那些行。

tel fred bert

打印包含 fred 的行随后是包含 bert 的行。

for 循环记号由 shell 识别并有一般形式

for name in w1 w2 ...
do command-list
done

命令列表(command-list)是由换行或分号分隔或结束的一个或多个命令的一个序列。进一步,保留字如 do 和 done 只有紧随一个换行或分号之后才被识别。名字(name)是一个 shell 变量,在每次执行 do 后面的命令列表时它将被依次设置为字 w1 w2 ...。如果省略了 in w1 w2 ... 则为每个位置参数执行一次循环;就是说,假定为 in $*。
使用 for 循环的另一个例子是 create 命令,它的文本是

for i do >$i; done

命令

create alpha beta

确保两个空文件 alpha 和 beta 存在并且是空的。使用记号 >file 主动的建立一个文件或清除它的内容。 还要注意在 done 之前需要一个分号(或换行)。


控制流 - case

case 记号提供一种多路分支。例如,

case $# in
1) cat >>$1 ;;
2) cat >>$2 <$1 ;;
*) echo \'usage: append [ from ] to\' ;;
esac

是一个 append 命令。在调用时带有一个实际参数如

append file

$# 是字符串 1 并使用 cat 命令把标准输入复制到 file 的末端。

append file1 file2

添加 file1 的内容到 file2 上。如果提供给 append 的实际参数数目不是 1 或 2 则打印指示正确用法的一个消息。

case 命令的一般形式是

case word in
pattern) command-list;;
...
esac
shell 按模式(pattern)出现的次序对每个模式尝试匹配字(word)。如果找到一个匹配则执行相关的命令列表(command-list)并且 case 的执行完成。因为 * 是匹配任何字符串的模式它可以用作缺省情况。

一句警告: shell 不做检查来确保只有一个模式匹配 case 实际参数。找到的一个匹配定义要执行的命令集。在下面的例子中在第二个 * 之后的命令将永不执行。

case $# in
*) ... ;;
*) ... ;;
esac

使用 case 构造的另一个例子是区别一个实际参数的不同形式。下列的例子是 cc 命令的一个片断。

for i
do case $i in
-[ocs]) ... ;;
-*) echo \'unknown flag $i\' ;;
*.c) /lib/c0 $i ... ;;
*) echo \'unexpected argument $i\' ;;
esac
done

为了允许同一个命令与多于一个模式相关联,case 命令提供了由 | 分隔的可选择的模式。例如,

case $i in
-x|-y) ...
esac

等价于

case $i in
-[xy]) ...
esac

使用普通的引用惯例所以

case $i in
\?) ...

将匹配字符 ?。



立即文档
shell 过程 tel 使用文件 /usr/lib/telnos 来为 grep 提供数据。一种替代方式是在这个 shell 过程中包含这些数据作为立即文档,如

for i
do grep $i <<!
...
fred mh0123
bert mh0789
...
!
done

在这个例子中 shell 接收在 <<! 和 ! 之间的行作为 grep 的输入。字符串 ! 是任意的,这个文档被由紧随 << 之后的字符串构成的一行所终结。

下面的过程 edg 展示了文档在提供给 grep 之前,要替换其中的参数。

ed $3 <<%
g/$1/s//$2/g
w
%

调用

edg string1 string2 file

等价于命令

ed file <<%
g/string1/s//string2/g
w
%

并在 file 中把所有出现的 string1 改变成 string2。使用 \ 引用特殊字符 $ 来防止替换如

ed $3 <<+
1,\$s/$1/$2/g
w
+

(这个版本的 edg 除了 ed 在没有字符串 $1 出现时打印一个 ? 之外等同于第一个版本)。通过引用终结字符串可以完全防止在立即文档内的替换,例如,

grep $i <<\#
...
#

文档被不加修改的提供给 grep。如果在立即文档中不需要参数替换,后一种形式更有效率。


shell变量
shell 提供字符串值的变量。变量名字开始于一个字母并由字母、数字和下划线组成。可以通过下列写法给出变量的值,例如,

user=fred box=m000 acct=mh0000

它向变量 user、box 和 acct 赋值。可以通过下列写法设置一个变量为空串,例如,

null=

通过把 $ 前导于变量的名字来把它替换成变量的值;例如,

echo $user

将回显 fred。

可以交互式的使用变量为经常使用的字符串提供简写。例如,

b=/usr/fred/bin
mv pgm $b

将把文件 pgm 从当前目录移动到目录 /usr/fred/bin。对于参数(或变量)替换可以有一种更一般的记号,如

echo ${user}

它等价于

echo $user

并在参数名字后跟随着一个字母或数字的时候有用。例如,

tmp=/tmp/ps
ps a >${tmp}a

将把 ps 的输出定向到文件 /tmp/psa,而

ps a >$tmpa

将导致替换变量 tmpa 的值。

除了 $? 下列都是由 shell 作最初的设置。$? 在每次命令执行之后设置。
$?
    最近执行的命令的退出状态(返回代码),是一个十进制数字符串。多数命令如果成功完成则返回一个零退出状态,否则返回一个非零退出状态。测试返回代码的值在以后的 if 和 while 命令中处理。
$#
    位置参数的数目(十进制)。例如用在 append 命令中检查参数的数目。
$$
    这个 shell 的进程编号(十进制)。因为过程编号在现存的进程中是唯一的,这个字符串经常用来生成唯一的临时文件名字。例如,

    ps a >/tmp/ps$$
    ...
    rm /tmp/ps$$

$!
    在后台运行的最后的进程的编号(十进制)。
$-
    当前的 shell 标志,比如 -x 和 -v。

一些变量对 shell 有特殊意义并应该避免作一般使用。

$MAIL
    在交互使用的时候,shell 在发出提示之前察看这个变量指定的文件。如果指定的文件自从上次察看之后已经被修改了,shell 在提示下一个命令之前打印消息 you have mail。 这个变量典型的在用户登录目录下的文件 .profile 中设置。例如,

    MAIL=/usr/mail/fred

$HOME
    cd 命令的缺省实际参数。使用当前目录来解析不以 / 开始的文件名引用,并使用 cd 命令变更它。例如,

    cd /usr/fred/bin

    使当前目录成为 /usr/fred/bin。

    cat wn

    将在终端上打印在这个目录中的文件 wn。命令。没有实际参数的 cd 等价于

    cd $HOME

    这个变量典型的也在这个用户的登录 .profile 中设置。
$PATH
    包含命令的目录的一个列表(查找路径)。shell 通过在这个目录列表中查找可执行文件来执行每个命令。如果未设置 $PATH 则缺省的查找当前目录、/bin 和 /usr/bin。否则$PATH 由用 : 分隔的目录名字组成。例如,

    PATH=:/usr/fred/bin:/bin:/usr/bin

    指定以当前目录(在第一个 : 之前的空串)、/usr/fred/bin、/bin 和 /usr/bin 的次序查找。在这种方式下单个用户可以有他们自己‘专有’命令,可在当前目录下单独访问。如果命令名字包含一个 / 则不使用这种目录查找;对执行这个命令作一次单一的尝试。
$PS1
    主要的 shell 提示字符串,缺省是‘$’。
$PS2
    在需要进一步输入时的 shell 提示,缺省是‘>’。
$IFS
    空白解释使用的字符集合




test命令

test 命令尽管不是 shell 的一部分,但意图由 shell 程序使用。例如,

test -f file

译注: 在当前版本的 shell 工具中,有一个与 test 等同的命令 [,它接受与 test 一样的实际参数,但要求在实际参数列表的最后附加一个 ] 作为实际参数。上面的例子也可以写成

[ -f file ]

如果 file 存在则返回零退出状态否则返回非零退出状态。通常 test 计算一个谓词并返回这个结果作为退出状态。下面给出某些经常使用的 test 实际参数
    test s
        如果实际参数 s 不是空串则为真
    test -f file
        如果 file 存在则为真
    test -r file
        如果 file 可读则为真
    test -w file
        如果 file 可写则为真
    test -d file
        如果 file 是目录则为真





猜你喜欢

转载自zhaodexin1129-126-com.iteye.com/blog/807745
今日推荐