我参与了将包含数百个ksh脚本的系统从AIX,Solaris和HPUX移植到Linux的过程。我发现ksh在两个系统上的行为方式存在以下差异:
1 2 3 4 5 6 7 8 9
| #!/bin/ksh
flag=false
echo"a
b" | while read x
do
flag=true
done
echo"flag = ${flag}"
exit 0 |
在AIX,Solaris和HPUX上,输出为" flag = true";在Linux上,输出为" flag = false"。
我的问题是:
-
是否可以设置环境变量以使Linux的ksh像
其他Os的?失败:
-
Linux的ksh上是否有一种选项可以获取所需的行为?失败:
-
是否有可用于Linux且具有所需行为的ksh实现?
其他说明:
-
在AIX,Solaris和HPUX上,ksh是ksh88的变体。
-
在Linux上,ksh是公共域ksh(pdksh)
-
在AIX上,Solaris和HPUX dtksh和ksh93(在其中安装了它们)与ksh一致
-
我可以访问的Windows NT系统:Cygwin和MKS NT与Linux一致。
-
在AIX,Solaris和Linux上,bash一致,给出错误的结果(从我看来)" flag = false"。
下表总结了系统存在的问题:
1 2 3 4 5 6 7 8 9 10 11
| uname -s uname -r which ksh ksh version flag =
======== ======== ========= =========== ======
Linux 2.6.9-55.0.0.0.2.ELsmp /bin/ksh PD KSH v5.2.14 99/07/13.2 false
AIX 3 /bin/ksh Version M-11/16/88f true // AIX 5.3
/bin/ksh93 Version M-12/28/93e true
SunOS 5.8, 5.9 and 5.10 /bin/ksh Version M-11/16/88i true
/usr/dt/bin/dtksh Version M-12/28/93d true
HP-UX B.11.11 and B.11.23 /bin/ksh Version 11/16/88 true
/usr/dt/bin/dtksh Version M-12/28/93d true
CYGWIN_NT-5.1 1.5.25(0.156/4/2) /bin/ksh PD KSH v5.2.14 99/07/13.2 false
Windows_NT 5 .../mksnt/ksh.exe Version 8.7.0 build 1859... false // MKS |
更新资料
经过我公司人员的一些建议后,我们决定对代码进行以下修改。无论使用"真实的" ksh(ksh88,ksh93)还是任何ksh克隆(pdksh,MSK ksh),这都给我们相同的结果。这对于bash也可以正常使用。
1 2 3 4 5 6 7 8 9 10
| #!/bin/ksh
echo"a
b"> junk
flag=false
while read x
do
flag=true
done < junk
echo"flag = ${flag}"
exit 0 |
感谢jj33先前接受的答案。
不要在Linux上使用pdksh,而要使用kornshell.org中的" real" ksh。 pdksh是ksh的盲目重新实现。 kornshell.org是原始的korn外壳,可追溯到25年左右(David Korn编写的外壳)。 AIX和Solaris使用的是原始ksh的版本,因此kornshell.org版本通常是功能完善且错误完整的。在使用SunOS / Solaris之后,安装kornshell.org ksh通常是在新的Linux机器上要做的第一件事...
经过我公司人员的一些建议后,我们决定对代码进行以下修改。无论使用"真实的" ksh(ksh88,ksh93)还是任何ksh克隆(pdksh,MSK ksh),这都给我们相同的结果。这对于bash也可以正常使用。
1 2 3 4 5 6 7 8 9 10
| #!/bin/ksh
echo"a
b"> junk
flag=false
while read x
do
flag=true
done < junk
echo"flag = ${flag}"
exit 0 |
感谢jj33为先前接受的答案。
这是回显" n"问题的另一种解决方案
脚步:
查找ksh软件包名称
$ rpm -qa --queryformat"%{NAME}-%{VERSION}-%{RELEASE}(%{ARCH})
" | grep"ksh"
ksh-20100621-19.el6_4.3(x86_64)
卸载ksh
$ sudo yum remove ksh-20100621-19.el6_4.3.x86_64
下载pdksh-5.2.14-37.el5_8.1.x86_64.rpm(请检查32位或64位操作系统并选择正确的pkg)
安装pdksh-5.2.14-37.el5_8.1.x86_64.rpm
$ sudo yum -y install /SCRIPT_PATH/pdksh-5.2.14-37.el5_8.1.x86_64.rpm
安装PDKSH之前的输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| $ ora_db_start_stop.sh
==============
Usage: START
==============
./ora_db_start_stop.sh START ALL
OR
./ora_db_start_stop.sh START ONE_OR_MORE
==============
Usage: STOP
==============
./ora_db_start_stop.sh STOP ALL
OR
./ora_db_start_stop.sh STOP ONE_OR_MORE |
安装PDKSH之后
==============
用法:START
./ora_db_start_stop.sh START ALL
要么
./ora_db_start_stop.sh START ONE_OR_MORE
==============
用法:停止
./ora_db_start_stop.sh STOP ALL
要么
./ora_db_start_stop.sh STOP ONE_OR_MORE
产生差异的原因是内部块是在原始Shell上下文中还是在子Shell中执行。您可以使用()和{}分组命令来控制它。就像您在更新中一样,使用临时文件在大多数情况下都可以使用,但是如果脚本快速运行两次,或者如果执行时没有清除文件,则将遇到问题。
1 2 3 4 5 6 7 8 9
| #!/bin/ksh
flag=false
echo"a
b" | { while read x
do
flag=true
done }
echo"flag = ${flag}"
exit 0 |
这可能有助于解决您在Linux ksh上遇到的问题。如果使用括号而不是括号,则将在其他ksh实现中获得Linux行为。
我在本地Ubuntu Hardy系统上安装了" ksh"和" pdksh"。
1 2
| ii ksh 93s+20071105-1 The real, AT&T version of the Korn shell
ii pdksh 5.2.14-21ubunt A public domain version of the Korn shell |
ksh具有您期望的"正确"行为,而pdksh没有。您可以检查本地Linux发行版的软件存储库中的"真实" ksh,而不使用pdksh。默认情况下," Real Unix"操作系统将安装Korn shell的AT&T版本,而不是pdksh,它们基于AT&T Unix(System V):-)。
您必须待在ksh内吗?
即使您使用相同的ksh,您仍然会调用各种外部命令(grep,ps,cat等),其中的一部分将具有不同的参数以及系统之间的不同输出。您要么必须考虑这些差异,要么使用每个差异的GNU版本来使它们相同。
Perl编程语言最初是专门为克服此问题而设计的。
它包括unix shell程序员希望从shell程序获得的所有功能,但是
在每个Unix系统上都是相同的。您可能没有所有这些的最新版本
系统,但是如果您需要安装某些软件,也许最好安装perl。
当zsh与emulate -L ksh选项一起使用时,脚本会提供正确的输出(true)。如果所有其他方法均失败,则您可能希望在Linux上尝试使用zsh。
我不知道有什么特定的选项可以强制ksh与特定的较旧版本兼容。就是说,也许您可??以在Linux机器上安装非常旧的ksh版本,并且其行为是否兼容?
在AIX / HP-UX盒子上安装更新版本的amy shell可能会更容易,而只需迁移脚本以使用sh。我知道有适用于所有平台的bash版本。