标准化您的 UNIX 命令行工具( 三 )


在 Solaris 上,killall 命令存在,但是将其用作关闭过程的一部分以终止所有进程 。设想在 Solaris 主机上意外调用 killall 命令以关闭所有 Apache 进程,没想到却实际上关闭了系统!
提供替代——在所有主机上使用相同的名称或使用不同的名称——可以实现按名称终止进程的预期结果,并消除不希望的和可能代价高昂的错误,同时扩展本身并不支持该选项的系统的功能 。
该命令的关键部分是能够识别正在运行的进程,提取与给定字符串匹配的进程,并使用 kill 命令将 KILL 信号发送到每个匹配进程 。在命令行上,您可以通过一系列管道实现等效的功能(使用 KILL 信号),如清单 5 所示 。
清单 5. 提供 killall 命令的替代
$ ps -ef|grep gcc|awk '{ print $2; }'|xargs kill -9
该命令的关键部分是提供给 grep(在此示例中为 gcc)的字符串和 ps 输出中包含所需进程 ID 的列 。上面的例子对 Solaris 主机和大多数 SVR4 Unix 变种有效 。
别名在此示例中无法工作,因为您希望能够插入命令中的信息不在结尾;别名所实现的是一种展开方法 。然而,内联外壳函数正好适合这种情况 。
【标准化您的 UNIX 命令行工具】在支持 Bourne 语法(bash 和 zsh)的外壳中,您可以使用清单 6 所示的以下语法来定义函数 。
清单 6. 定义函数
function NAME()
{
# do stuff here
}
调用函数时,函数参数作为 $1、$2 等形式来提供,就像在典型的外壳脚本中一样 。因此,您可以定义一个函数,使其执行与 killall 相同的基于字符串的信号发送功能(请参见清单 7) 。
清单 7. 定义一个执行与 killall 相同的信号发送功能的函数
function killall()
{
ps -ef|grep $1|awk '{ print $2; }'|xargs kill -9
}
请注意,该函数的 awk 部分中的 $2 不会展开,因为您已经对 awk 脚本定义使用了单引号,这样阻止了展开,并且在此示例中会挑选第二列 。
与别名一样,指定外壳函数的最佳位置是在外壳的初始化脚本中 。函数的局限性在于,它们依赖外壳提供支持能力,而这并不总是可能或可用 。
虽然可以随心所欲地使内联外壳函数变得任意长,但在许多情况下,外壳函数并不理想 。例如,在模拟更复杂的命令或提供命令包装的超长序列中,您需要分析选项并提供本地化的等效命令,此时内联函数就没有多大用处了 。在这种情况下,外壳脚本可能更为适合 。
使用脚本
构建一致环境的最容易和最兼容的方法,是创建可用作实际命令的包装的外壳脚本,这样考虑了您希望支持的各种选项和设置 。
例如,useradd 和 adduser 命令在设置参数(如用户 ID 或组成员资格)时支持同样的单字母命令行选项,因此 Linux 上的 $ adduser -u 1000 -G sales,marketing mcbrown 等效于 Solaris 上的 $ useradd -u 1000 -G sales,marketing mcbrown 。
然而,Linux 版本还支持扩展命令选项,例如,--uid 和 --groups 等效于上面的命令行选项 。这些扩展选项在 Solaris 上不受支持,但是,如果创建一个名为 adduser 的外壳脚本,您就可以模拟 Linux 版本,然后用适当的选项运行实际的 Solaris useradd 命令 。
清单 8 是用作 adduser 或 useradd 命令的包装的示例外壳脚本 。
清单 8. 用作包装的示例外壳脚本
#!/bin/bash
# -*- shell-script -*-
for i in $*
do
 case $i in
 --uid|-u) OPT_UID=$2; shift 2;;
 --groups|-G) OPT_GROUPS=$2; shift 2;;
 --gid|-g) OPT_GROUP=$2; shift 2;;
 --home-dir|-d) OPT_HOMEDIR=$2; shift 2;;
 --shell|-s) OPT_SHELL=$2;shift 2;;
 --non-unique|-o) OPT_NONUNIQUE=1;shift 2;;

推荐阅读