我有两台服务器,一台是 AIX,带有默认 shell ksh,另一台是 RHEL,带有默认 shell bash。
我有一个安装在两者上的脚本,它将运行类似的命令,但适用于 AIX 或 Linux。该脚本无法在 bash 服务器上运行,有没有办法让该脚本在 bash 和 ksh 上运行,或者最好的选择是创建两个不同的脚本?
#!/usr/bin/ksh
export OS=`uname -s`
echo "OS is "$OS"."
case $OS in
"AIX")
#run AIX commands;;
"Linux")
#run Linux commands;;
"*")
echo "Exiting. The OS type is not found.";;
esac
echo "Done."
exit 0
更新
我需要运行的命令适用于每台服务器上的用户帐户。解锁帐户的示例。 AIX /usr/bin/chuser account_locked=false $USERNAME
Linux /usr/bin/passwd -u $用户名
通过进一步调查,我发现AIX中的shell位置位于/usr/bin/sh,而Redhat的shell位置位于/bin/sh。
我可以根据“uname”的结果定义shebang吗?
答案1
迄今为止最简单的方法是在两个系统上使用相同的 shell。仅仅因为预安装了一个 shell(脚本没有“默认 shell”之类的东西,shell 就是 shebang 行所说的任何内容)并不意味着您不能安装其他 shell。您可以在 AIX 上安装 bash(从工具箱,例如),或适用于 Linux 的 ksh93(使用您的发行版的包管理器:安装包ksh
)。
如果您选择 ksh,请注意/usr/bin/ksh
AIX 上是 ksh88。 Linux 上没有 ksh88 版本,只有 ksh93,它在/usr/bin/ksh93
AIX 上可用。
如果将相同的 shell 安装在两个系统上的相同位置(符号链接即可)会更容易,这样您就可以在 shebang 行中使用相同的路径。如果拥有相同的位置太困难,您可以使用类似的东西#!/usr/bin/env bash
,只要您确保它bash
位于PATH
两个系统上。如果您因为没有 root 访问权限而必须在主目录中安装 bash 或 ksh,这可能会很有用。
如果您确实无法在两台机器上安装相同的 shell(大概是因为有一些愚蠢的合规性规则只会使人们的生活变得复杂,但又太根深蒂固而无法推翻),您有几种可能性。
- 用作
#!/bin/sh
您的系统提供的交叉线和程序。所有现代 UNIX 系统都提供POSIX外壳作为/bin/sh
。在 AIX 上,/bin/sh
是 ksh88。在 Red Hat 上,/bin/sh
是 bash (当作为 调用时,其行为略有不同sh
)。请注意,在某些其他操作系统上(例如,在许多 Linux 发行版上),/bin/sh
是一个较小的 shell,它可能不比 POSIX 功能多多少。 使用一些样板代码来启动脚本,这些代码会寻找更好的 shell 并执行它。
#!/bin/sh if [ -n "$BASH" ]; then … bash compatibility code … elif type whence >/dev/null 2>/dev/null; then … ksh compatibility code … elif type ksh93 >/dev/null 2>/dev/null; then exec ksh93 "$0" "$@" elif type ksh >/dev/null 2>/dev/null; then exec ksh "$0" "$@" elif type mksh >/dev/null 2>/dev/null; then exec mksh "$0" "$@" elif type bash >/dev/null 2>/dev/null; then exec bash "$0" "$@" else echo 1>&2 "Cannot find ksh or bash, aborting" exit 125 fi
无论哪种情况,ksh88 和 bash 的交集都提供了一些超出 POSIX 的有用功能,但您可能需要一些兼容性代码。尤其:
- ksh88 中的数组赋值使用
set -A
.看不同ksh环境下的赋值变量 - 局部变量由 声明
typeset
。 - Ksh88 没有
${VAR/PATTERN/REPLACEMENT}
,$'…'
或FIGNORE
。它确实有[[ … ]]
。 - 要
@(…)
在 bash 中启用 ksh 和其他 ksh 扩展模式,请运行shopt -s extglob
.
答案2
拥有两个单独版本的脚本可能会更容易。由于它很短,因此可能不值得添加额外的代码来处理 jw013 建议的两种格式之间的差异。另一方面,如果您有一个更大的脚本,那么拥有一个脚本并让脚本根据其运行位置执行不同的命令可能会更容易。
答案3
我有类似的要求 - 我需要在 AIX 5.3 上使用 ksh93 来支持关联数组。因此,我设置了脚本以使用 ksh93 启动第二个实例。我还添加了一个保护措施,以防止它一遍又一遍地重生。
#!/bin/ksh
scr=$0
safe=$1
echo "Check OS to determine if ksh93 is needed..."
if ( `typeset -A testvar > /dev/null 2>&1` ); then
echo "Associative array functions supported."
else
echo "Associative array functions NOT supported. Starting second instance with ksh93..."
if [ "$safe" -eq 1 ]; then
echo "SECOND INSTANCE ALREADY STARTED!"
exit 1
else
echo "BEGIN SECOND INSTANCE USING KSH93"
/bin/ksh93 $scr 1
exit 0
fi
fi
答案4
吉尔斯的答案(恕我直言)非常出色(一如既往),但由于您没有选择它,甚至没有投票赞成它,也许您发现它太复杂了。因此,这里有一些(简单的)要点可能有帮助,也可能没有帮助,并且可能会帮助您避免维护两个单独的脚本,这对于必须长期维护的大型脚本来说可能会变得疯狂。
1) AIX 计算机可能已bash
安装,即使它不是交互式使用的默认 shell。 (我使用的 AIX 机器确实已经bash
安装了,但我不知道它是否是系统管理员添加的。我猜它是这样安装的,因为我们所有的系统管理员都是ksh
瘾君子。)我愿意打赌 RHEL 机器已经ksh
安装。检查此项,因为如果您可以在两台机器上使用相同的 shell,它将为您节省很多的麻烦。
2) 如果您不知道 shell 将安装在哪里,请避免将其路径直接放在 shebang 行中。而是在后面输入路径env
和 shell 可执行文件名称,如下所示:
#!/usr/bin/env bash
这应该在两台机器上都可以工作,但你必须对其进行测试才能确定。 (据称, 的位置比或大多数其他事物env
的位置更标准。)bash
一旦您在两台机器上使用相同的 shell,问题可能就解决了。但如果不...
3) 您可以将特定于平台的代码分解为源代码到主脚本中的函数。这意味着虽然脚本可能有地段由于运行在 AIX 还是 RHEL 上,事情的工作方式有所不同,因此您无需重复检查平台。只需执行一次,并获取适当的函数:
case $OS in
"AIX")
source aix_functions;;
"Linux")
source redhat_functions;;
"*")
echo "Exiting. The OS type is not found.";;
esac
现在,您可以在整个脚本中使用您获取的任何函数,而无需使用其他case
语句来区分平台:
do_something_platform_specific "$SOME_ARGUMENT" "$SOME_OTHER_ARGUMENT"