7

私は、いくつかの ksh スクリプトを含むシステムを AIX 6.1 から SUSE-Linux に移植するプロセスに携わっています。2 つのシステムでの 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 で目的の動作を得るには、コードをどのように変更する必要がありますか?

ノート:

  • すでに「ローカル」で変数を宣言しようとしましたが、Linux ではエラーが返されましたが、AIX では機能します。

次の表は、2 つのシステムをまとめたものです。

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

1 に答える 1

4

TL;DR : 些細なケースの場合: 関数定義構文を からf() compound-commandに切り替えますfunction f { ...; }。複雑なケースの場合: ksh93 のみに依存し (はるかに柔軟)、以下のばかげたハックを使用し (困難)、厳密に POSIX に準拠するように書き直します (おそらく困難で柔軟性がありません)、実際の言語で書き直します (ただし、シェルは場合によっては便利です)。

「Linux ksh」はありません。すべてのシステムで同じように動作し、使用しているバージョンにのみ依存します。

AIX は、変更された ksh88 を出荷します。ksh88 には動的スコープ システムがあり、Bash やローカルをサポートする他のすべてのシェルに似ていますが、ksh93 とは異なります。ローカルが ksh93 の下でfunction name { ; }機能するには、関数を定義するために POSIX 構文ではなく、「最新の」構文を使用する必要があります。ksh88 は独自のソフトウェアであり、最新の x86 ハードウェアで実行するように構築されていない可能性が高いため、文書化されておらず、テストする方法がないため、これは ksh88 で必要な場合とそうでない場合があります。

上記が正しく、スクリプトが ksh88 用に作成されている場合、ローカル変数が少なくとも機能するには、関数定義構文を切り替えるだけで十分です。ただし、ksh93 の静的スコープは他のシェルの動的スコープよりもはるかに優れていますが、深刻な移植性の問題を引き起こします。これはおそらく、すべてのシェル スクリプトで回避するのが最も難しい問題の 1 つです。

移植可能なローカルが必要な場合、素晴らしい解決策はありません。kshスコープを「壊して」ksh88/bash/mksh/zshなどのようにする2つの手法を思いつきました。

最初のものは壊れていない 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 '"$@"'
    fi
}

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

2 番目の方法は、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+"${y@Q}"} "$y")"
}


f

移植性も必要な堅牢なライブラリ コードを記述する必要がある数少ないユーザーの 1 人である場合にのみ、これらのいずれかをお勧めします。

于 2013-03-28T12:44:54.180 に答える