当前位置:首页> 正文

如何克服Linux上的ksh与AIX / Solaris / HPUX上安装的ksh之间的不兼容?

如何克服Linux上的ksh与AIX / Solaris / HPUX上安装的ksh之间的不兼容?

How to overcome an incompatibility between the ksh on Linux vs. that installed on AIX/Solaris/HPUX?

我参与了将包含数百个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。


    zshemulate -L ksh选项一起使用时,脚本会提供正确的输出(true)。如果所有其他方法均失败,则您可能希望在Linux上尝试使用zsh


    我不知道有什么特定的选项可以强制ksh与特定的较旧版本兼容。就是说,也许您可??以在Linux机器上安装非常旧的ksh版本,并且其行为是否兼容?

    在AIX / HP-UX盒子上安装更新版本的amy shell可能会更容易,而只需迁移脚本以使用sh。我知道有适用于所有平台的bash版本。


    展开全文阅读

    相关内容