|
本文介绍用于标准化界面以简化在不同 UNIX® 系统之间移动的方法。如果您管理多种 UNIX 系统(特别是在异构环境中),则最艰巨的任务可能是在不同环境之间切换并执行不同的任务,同时还必须考虑系统之间的所有差异。本文并不介绍特定的差异,而是研究能够提供兼容层(或包装)以支持一致环境的方法。 关于本系列 典型的 UNIX® 管理员拥有一套经常用于辅助管理过程的关键实用工具、诀窍和系统。存在各种用于简化不同过程的关键实用工具、命令行链和脚本。其中一些工具来自于操作系统,而大部分的诀窍则来源于长期的经验积累和减轻系统管理员工作压力的要求。本系列文章主要专注于最大限度地利用各种 UNIX 环境中可用的工具,包括简化异构环境中的管理任务的方法。 差异和问题 如果您使用多种 UNIX 主机,特别是每种主机都支持不同的 UNIX 风格(Berkeley Software Distribution (BSD)、UNIX System Release 4 (VSVR4) 等)或版本,您也许发现自己要花大量的时间来检查和确定自己所在的主机类型,以便能够适应系统操作方式的变化。 例如,ps 命令在基于 BSD 和基于 SVR4 的 UNIX 主机上,分别需要不同的命令行选项来获得大致相同的信息(有关更多细节,请参阅 系统管理员工具包: 进程管理技巧)。平台之间还存在更广泛的差异。有时,这种差异是命令名称发生了更改;Linux® 提供 adduser 命令,而 Solaris 则提供 useradd 命令。 就标准化而言,有多种方法可供您采用。 - 您可以选择对主要平台(例如 Solaris)进行标准化,并在其他平台上提供等效命令的包装以匹配 Solaris 标准。
- 也可以选择对为所使用的任务提供最佳组合的命令集进行标准化,挑选您喜欢的命令并为特定平台上不存在的命令构建包装。
- 您可以创建自己的一套执行特定任务的脚本(包括您自己用于
ls、ps 等常用工具的替代脚本),以便它们生成您想要的信息。这样做有点危险,原因是它意味着您可能从未使用原始命令,从而可能在您的脚本不可用时导致潜在的问题。
如何具体实现各个命令的包装以提供一个兼容或唯一的层,这取决于您是尝试简单地为功能相同的替代命令提供一个公认名称,还是需要构建一个或多个命令的包装以获得等效的结果。可能的解决方案有三种: - 别名——这种解决方案仅在某些外壳中受支持——别名提供了将给定的字符串展开为特定命令的简单方法。
- 外壳函数——大多数现代外壳都支持这种解决方案——外壳函数使您能够创建更复杂的序列,但是由于它们作为内置函数运行,在差异相当小时可能更为实用。
- 外壳脚本——当您要构建的包装特别复杂时,更好的解决方案是使用外壳脚本,您可以代替原始命令调用这些脚本。使用外壳脚本,您可以更创造性地处理替代,甚至为另一个命令提供完全由外壳脚本驱动的替代。
让我们研究一下每种可能的解决方案和一些可通过此方法来进行模拟的示例命令。 使用别名 别名在 Korn (ksh)、Bourne-Again SHell (bash)、TENEX C shell (tcsh) 和 Z shell (zsh) 外壳中受支持,当您希望设置命令的特定选项,同时仍然支持其他选项时,别名提供了也许是最简单的方法。顾名思义,您可以将一个命令用作另一个命令的别名,或者为带有附加选项的同一个命令提供别名。别名从您键入的内容展开为其展开形式。 例如,一个常用的别名是 ll,它调用等效的 ls -l(ll 通常称为长清单 (long listing))。每当用户键入 ll,就会直接将其替换为展开形式,因此:$ ll a* 在执行前展开为:$ ls -l a*。 命令行选项也仍然有效,换句话说,$ ll -a 展开为:$ ls -l -a。 还可以为现有命令设置别名;假设将 -F 选项添加到所有 ls 命令,这样,$ ls 将展开为:$ ls -F。 要设置别名,请使用内置的外壳 alias 语句,并在引号中指定所需的展开形式。例如,要设置前面详细描述的 ll 的展开形式,可使用:$ alias ll='ls -l'。 别名在以下情况下最为有用:您希望使用 base 命令并容易地指定附加选项,同时仍然允许设置特定于平台的选项。 一个很好的例子就是 ps 命令,它在基于 SVR4 和基于 BSD 的 UNIX 主机上是不同的。在本系列的第一篇文章中,请参阅 系统管理员工具包: 进程管理技巧 ——这篇文章解释了如何使用 ps 的选项来获得相似的清单。您可以结合别名使用那些选项,而不会影响您指定附加选项的能力。例如,在 BSD 上,您将如清单 1 所示指定别名。 清单 1. 在 BSD 上指定别名
$ alias ps='ps -o pid,ppid,command'
而在 SVR4 主机上,您将如清单 2 所示创建别名。 清单 2. 在 SVR4 上指定别名
$ alias ps='ps -opid,ppid,cmd
现在,在这两个系统对 ps 的不同操作方式的限制下,您获得了 ps 产生的标准输出。和前面一样,您可以继续添加更多选项;例如,在安装了该别名的任一个平台上请求所有进程,添加 -A 选项就是这样一种情况。这会在 BSD(在此示例中为 Mac OS X)上产生类似于清单 3 的输出。 清单 3. 在 BSD 上使用 -A 选项
$ ps -A
PID PPID COMMAND
1 0 /sbin/launchd
23 1 /sbin/dynamic_pager -F /private/var/vm/swapfile
27 1 kextd
32 1 /usr/sbin/KernelEventAgent
33 1 /usr/sbin/mDNSResponder -launchdaemon
34 1 /usr/sbin/netinfod -s local
35 1 /usr/sbin/syslogd
36 1 /usr/sbin/cron
37 1 /usr/sbin/configd
38 1 /usr/sbin/coreaudiod
39 1 /usr/sbin/diskarbitrationd
...
SVR4 系统(Gentoo Linux 主机)会显示同样的列,如清单 4 所示。 清单 4. 在 SVR4 上使用 -A 选项
$ ps -A
PID PPID CMD
1 0 init [3]
2 1 [migration/0]
3 1 [ksoftirqd/0]
4 1 [watchdog/0]
5 1 [migration/1]
6 1 [ksoftirqd/1]
7 1 [watchdog/1]
8 1 [events/0]
9 1 [events/1]
10 1 [khelper]
11 1 [kthread]
14 11 [kblockd/0]
15 11 [kblockd/1]
16 11 [kacpid]
...
另一个选项或多或少地镜像了本文其他地方给出的脚本和函数解决方案。该选项是为给定命令的特定输出创建别名,这些别名采用同一方法来提供相同的格式化输出。同样以 ps 为例,您可以创建别名 ps-all 来输出所有进程列表,并根据需要为每种平台设置相应的展开形式。 设置这些别名的最佳位置是在登录期间执行的外壳初始化脚本中,例如 .ksh、.profile 或 .bashrc。您可以在这些脚本中执行同样的系统检查,以验证要启用哪些别名。如果希望提供适用于所有用户的全局解决方案,则应将别名定义放在公开可用的文件中(例如放在 /etc or /usr/local 中),并设置用户初始化脚本以获得别名定义来源。 别名机制最适合于您希望设置单个命令的命令行选项的情况,虽然也可以使用它们来将给定的命令展开为一组命令或管道。这样削弱了为展开形式中除最后一个命令以外的其他任何命令指定附加参数的能力。对于处理此类包装,外壳中的内联函数可能更为适合。 使用内联外壳函数 大多数外壳都支持函数,这些函数本质上是微型脚本,您可以在其中放置命令和其他外壳脚本元素以执行特定的任务。由于它们是主外壳定义中的函数,因此使用起来方便快捷,同时仍然支持许多完整外壳脚本所具有的相同功能,如命令行参数。 对于支持别名无法在其中工作的某些命令和组合,对命令行参数的支持非常关键。例如,killall 命令最基本的功能是终止所有与特定字符串匹配的命令。该命令并非在所有平台上都可用,但是一旦您了解了它,就会希望在其他环境中使用它。 在 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 变种有效。 别名在此示例中无法工作,因为您希望能够插入命令中的信息不在结尾;别名所实现的是一种展开方法。然而,内联外壳函数正好适合这种情况。 在支持 Bourne 语法(bash 和 zsh)的外壳中,您可以使用清单 6 所示的以下语法来定义函数。 清单 6. 定义函数
function NAME()
{
# do stuff here
}
调用函数时,函数参数作为 $1、$2 等形式来提供,就像在典型的外壳脚本中一样。因此,您可以定义一个函数,使其执行与 killall 相同的基于字符串的信号发送功能(请参见清单 7)。 Linux联盟收集整理
 |
频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意。
| 原始作者:佚名 |
录入时间:2007-1-2 3:19:22 |
| 信息来源:不详 |
投稿信箱:itqoo@126.com |
|
|
 |
|