2013-03-28 80 views
7

我参与了将包含多个ksh脚本的系统从AIX 6.1移植到SUSE-Linux的过程。我所遇到下列差异KSH的方式在两个系统上的行为:如何防止Linux上的ksh通过局部变量覆盖全局变量?

# LocalVar.sh 

test_loc_var() 
{ 
typeset -t var 
var=localvariable 
echo "var = $var" 
} 

typeset var=globalvariable 

echo "var = $var" 
test_loc_var 
echo "var = $var" 

在AIX上正确的结果是:

var = globalvariable 
var = localvariable 
var = globalvariable 

Linux上的错误的结果是:

var = globalvariable 
var = localvariable 
var = localvariable 

我的问题是:

  • 是我可以设置一个环境变量来让Linux的ksh在AIX上表现得像AIX一样?不及格:
  • 在Linux的ksh上有一个选项可以获得所需的行为吗?否则:
  • 代码中有哪些更改需要我去做,以便在Linux上获得所需的行为?

注:

  • 我已经尝试声明具有“本地”的变量,但在Linux上返回一个错误,在AIX上它的工作原理。

下表总结了两种系统:

uname -s     | Linux     AIX   
uname -r     | 2.6.16.60-0.54.5-smp  1 
which ksh    | /bin/ksh     /usr/bin/ksh 
rpm -qa | grep -i ksh | ksh-93s-59.11.35   - 
lslpp -l | grep -i ksh | -      bos.rte.shell 6.1.8.15 APPLIED Shells (bsh, ksh, csh) 

回答

4

TL; DR:对于简单的情形:开关函数定义的语法从f() compound-commandfunction f { ...; }。对于复杂的情况:依靠ksh93的只(更灵活),可以使用下面的荒谬黑客(硬),重写要严格POSIX符合(也许硬,不灵活),重写一个真正的语言(但壳很不错有时)。

没有“Linux ksh”。它在所有系统上表现相同,只取决于您使用的版本。

AIX发布了修改的ksh88。 ksh88有一个动态范围系统,类似于Bash和所有其他支持本地的shell,但与ksh93不同。为了让本地人在ksh93下工作,您必须使用“现代”语法,而不是POSIX语法来定义函数。这在ksh88中可能需要也可能不需要,因为它没有文档记录,也没有可能的方式供我测试,因为ksh88是专有软件,并且很可能甚至不能在现代x86硬件上运行。

如果上述内容是正确的,并且您的脚本是为ksh88编写的,那么只需切换函数定义语法就足以让本地变量至少起作用。然而,尽管ksh93的静态作用域远远优于其他shell的动态作用域,但确实造成了严重的可移植性问题 - 可能是所有shell脚本中最难解决的问题之一。

如果您需要便携式当地人,那么没有太棒的解决方案。我想出了两种技术,其“破发”的ksh范围更像ksh88 /庆典/ mksh/zsh,使用等

在非打破POSIX壳的首部作品。

#!/bin/sh 
# (Partially) Working shells: dash, posh, bash, ksh93v, mksh, older zsh 
# Broken shells: current zsh, busybox sh, non-bleeding edge alpha ksh93, heirloom 

f() { 
    if ! ${_called_f+false}; then 
     # Your code using "x" 
     for x; do 
      printf '%s, ' "$x" 
     done 
    else 
     # This hackishly localizes x to some degree 
     _called_f= x= command eval typeset +x x 2\>/dev/null \; f '"[email protected]"' 
    fi 
} 

# demonstration code 
x='outside f'; printf "$x, "; f 1 2 3; echo "$x" 

第二种方法只适用于KSH般的炮弹和包括通过参考明确地传递一切,用间接广泛。

#!/usr/bin/env ksh 
# bash, ksh93, mksh, zsh 
# Breaking things for dash users is always a plus. 

# This is crude. We're assuming "modern" shells only here. 
${ZSH_VERSION+false} || emulate ksh 
${BASH_VERSION+shopt -s lastpipe extglob} 
unset -v is_{ksh93,mksh} 
case ${!KSH_VERSION} in 
    .sh.version) is_ksh93= ;; 
    KSH_VERSION) is_mksh= 
esac 

function f { 
    # We want x to act like in dynamic scope shells. (not ksh93) 
    typeset x 
    g x 
    typeset -p x 
} 

function g { 
    # Note mksh and bash 4.3 namerefs kind of suck and are no better than eval. 
    # This makes a local of a pointer to the variable arg of the same name. 
    # Remember it's up to the programmer to ensure the sanity of any NAME 
    # passed through an argument. 

    ${is_ksh93+eval typeset -n ${1}=\$1} 
    typeset y=yojo 

    # mksh... you fail at printf. We'll try our best anyway. 
    eval "$(printf %${is_mksh+.s%s=%s%.s }s=%q "$1" ${is_mksh+"${[email protected]}"} "$y")" 
} 


f 

,如果你需要编写必须是便携式太强大的库代码为数不多的我只建议您考虑以下。

+0

你好Ormaaj,非常感谢你的详细和非常有帮助的答案。似乎是我有错误的期望,还有更多的事情要做,比我希望的要多。但是现在我知道至少在移民过程中如何处理未来的问题。 – Cologne2202 2013-03-28 16:15:50