我参与了将包含几百个ksh脚本的系统从AIX,Solaris和HPUX移植到Linux的过程。 我已经遇到了ksh在两个系统上行为方式的差异:
#!/bin/ksh flag=false echo "a\nb" | while read x do flag=true done echo "flag = ${flag}" exit 0
在AIX,Solaris和HPUX上,Linux上的输出为“flag = true”,输出为“flag = false”。
我的问题是:
其他说明:
下表总结了系统的问题:
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
经过我公司的人的一些build议,我们决定对代码进行如下修改。 无论使用“真实”ksh(ksh88,ksh93)还是任何ksh克隆(pdksh,MSK ksh),这都给了我们相同的结果。 这也适用于bash。
#!/bin/ksh echo "a\nb" > junk flag=false while read x do flag=true done < junk echo "flag = ${flag}" exit 0
感谢jj33以前接受的答案。
而不是在linux上使用pdksh,使用kornshell.org上的“真正的”ksh。 pdksh是ksh的盲目重新实现。 kornshell.org是可以追溯到25年左右的原始科恩贝壳(大卫·科恩的作品)。 AIX和Solaris使用原始版本的ksh,因此kornshell.org版本通常是功能和错误的完整版本。 在使用SunOS / Solaris之后,安装kornshell.org ksh通常是我在新的Linux机器上做的第一件事情。
经过我公司的人的一些建议,我们决定对代码进行如下修改。 无论使用“真实”ksh(ksh88,ksh93)还是任何ksh克隆(pdksh,MSK ksh),这都给了我们相同的结果。 这也适用于bash。
#!/bin/ksh echo "a\nb" > junk flag=false while read x do flag=true done < junk echo "flag = ${flag}" exit 0
感谢之前接受的答案jj33。
我在本地Ubuntu Hardy系统上安装了“ksh”和“pdksh”。
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。 “真正的Unix”操作系统将安装Korn shell的AT&T版本,而不是pdksh,默认情况下,它们是基于AT&T Unix(System V):-)。
不同的原因在于,内部块是在原始shell上下文中还是在子shell中执行。 您可以使用()和{}分组命令来控制它。 使用临时文件,就像在更新中一样,大部分时间都可以使用,但是如果脚本快速运行两次,或者在不清除文件的情况下执行,将会遇到问题。
#!/bin/ksh flag=false echo "a\nb" | { while read x do flag=true done } echo "flag = ${flag}" exit 0
这可能有助于解决您在Linux ksh上遇到的问题。 如果使用圆括号代替大括号,则会在其他ksh实现上获得Linux行为。
这是echo“\ n”问题的另一个解决方案
脚步:
$ rpm -qa --queryformat "%{NAME}-%{VERSION}-%{RELEASE}(%{ARCH})\n" | grep "ksh" ksh-20100621-19.el6_4.3(x86_64)
卸载ksh $ sudo yum remove ksh-20100621-19.el6_4.3.x86_64
down load 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安装之前输出
$ ora_db_start_stop.sh \n============== Usage: START ==============\n\n ./ora_db_start_stop.sh START ALL \n OR \n ./ora_db_start_stop.sh START ONE_OR_MORE \n \n============== Usage: STOP ==============\n\n ./ora_db_start_stop.sh STOP ALL \n OR \n ./ora_db_start_stop.sh STOP ONE_OR_MORE \n\n
PDKSH安装后
==============
./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
我不知道有什么特别的选择强迫ksh与特定的旧版本兼容。 也就是说,也许你可以在你的Linux机器上安装一个非常旧的ksh版本,并以兼容的方式运行?
在AIX / HP-UX机器上安装更现代的amy shell版本可能更容易,只是将脚本迁移到使用sh。 我知道所有平台都有可用的bash版本。
当zsh
与emulate -L ksh
选项一起使用时,您的脚本会给出正确的(true)输出。 如果一切都失败了,你可能希望尝试在Linux上使用zsh
。
你必须留在ksh内吗?
即使你使用相同的ksh,你仍然会调用各种外部命令(grep,ps,cat等),其中一部分会有不同的参数和不同的系统输出。 要么你必须考虑到这些差异,或者使用它们中的每一个的GNU版本来使事情一致。
Perl编程语言最初的设计正是为了克服这个问题。 它包含了unix shell程序员希望从shell程序中获得的所有功能,但是在每个Unix系统上都是一样的。 您可能没有在所有这些系统上的最新版本,但如果您需要安装的东西,也许最好是安装Perl。