如何防止Linux上的ksh通过局部变量覆盖全局变量?

我参与了将包含几个ksh脚本的系统从AIX 6.1移植到SUSE-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上表现得像? 否则:
  • Linux的ksh上有一个选项可以获得所需的行为吗? 否则:
  • 为了在Linux上获得所需的行为,代码中需要做哪些改变?
  • 注意:

  • 我已经尝试用“local”声明变量,但是它在AIX上运行时在Linux上返回了一个错误。
  • 下表总结了这两个系统:

    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)
    

    TL; DR :对于微不足道的情况:将函数定义语法从f() compound-command切换到function f { ...; } function f { ...; } 。 对于复杂的情况:依赖ksh93-only(更灵活),使用下面的荒谬黑客(难),重写严格符合POSIX(可能很难,不灵活),用真实语言重写(但shell有时很好)。

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

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

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

    如果您需要便携式本地人,那么没有太棒的解决方案。 我已经想出了两个技术,它们可以“破解”ksh作用域,使其更像ksh88 / bash / mksh / zsh等。

    第一个作品在非破坏的POSIX shell中运行。

    #!/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 '"$@"'
        fi
    }
    
    # demonstration code
    x='outside f'; printf "$x, "; f 1 2 3; echo "$x"
    

    第二种方法只能在类似ksh的shell中工作,并且涉及通过引用显式传递所有内容并广泛使用间接引用。

    #!/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+"${y@Q}"} "$y")"
    }
    
    
    f
    

    如果你是少数需要编写强健的库代码的人,那么我只推荐其中之一。

    链接地址: http://www.djcxy.com/p/70253.html

    上一篇: How to prevent ksh on Linux to overwrite a global varibale by a local variable?

    下一篇: How to get current page path in jQuery (while doing ajax call)