2013-03-28 9 views
7

Ich bin an der Portierung eines Systems beteiligt, das mehrere ksh-Skripte von AIX 6.1 nach SUSE-Linux enthält. Ich habe über die folgenden Unterschied kommen in der Art und Weise KSH auf den beiden Systemen verhält:Wie verhindert man, dass ksh unter Linux eine globale Variable durch eine lokale Variable überschreibt?

# 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" 

Das richtige Ergebnis auf AIX ist:

var = globalvariable 
var = localvariable 
var = globalvariable 

das falsche Ergebnis auf Linux ist:

var = globalvariable 
var = localvariable 
var = localvariable 

Meine Fragen sind:

  • Ist gibt es eine Umgebungsvariable, die ich einstellen kann, um Linux ksh zu erhalten, um sich wie auf AIX zu verhalten? Failing that:
  • Gibt es eine Option auf Linux ksh, um das erforderliche Verhalten zu erhalten? Failing that:
  • Welche Änderungen im Code muss ich tun, um das gewünschte Verhalten auf Linux zu bekommen?

Hinweis:

  • Ich habe bereits versucht, die Variable mit "local" zu erklären, aber das hat einen Fehler zurückgegeben unter Linux, AIX funktioniert es.

Die folgende Tabelle fasst die zwei Systeme:

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) 

Antwort

4

TL; DR: Für triviale Fälle: Schalten Funktionsdefinition Syntax von den f() compound-command zu function f { ...; }. Für komplexe Fälle: Abhängig von ksh93-only (viel flexibler), benutze die folgenden Absurd-Hacks (hart), schreibe streng POSIX-konform (vielleicht hart, unflexibel), schreibe in einer echten Sprache um (aber Shells sind manchmal nett).

Es gibt kein "Linux ksh". Es verhält sich auf allen Systemen gleich und hängt nur von der Version ab, die Sie verwenden.

AIX liefert ein modifiziertes ksh88. ksh88 hatte ein dynamisches Scope-System, ähnlich wie Bash und alle anderen Shells, die Locals unterstützen, aber im Gegensatz zu ksh93. Damit Einheimische unter ksh93 arbeiten können, müssen Sie die "moderne" function name { ; }-Syntax anstelle der POSIX-Syntax verwenden, um Funktionen zu definieren. Dies kann in ksh88 erforderlich sein oder auch nicht, da es nicht dokumentiert ist und es keine Möglichkeit für mich gibt zu testen, da ksh88 proprietäre Software ist und höchstwahrscheinlich nicht einmal für den Betrieb auf moderner x86-Hardware entwickelt wurde.

Wenn das oben genannte korrekt ist und Ihre Skripte für ksh88 geschrieben wurden, genügt es, die Funktionsdefinitionssyntax zu wechseln, damit lokale Variablen zumindest funktionieren. Während jedoch der statische Bereich von ksh93 dem dynamischen Umfang anderer Shells weit überlegen ist, verursacht er ein ernsthaftes Portabilitätsproblem - wahrscheinlich eines der am schwierigsten zu behandelnden in allen Shell-Skripten.

Wenn Sie tragbare Einheimische benötigen, gibt es keine fantastischen Lösungen. Ich habe zwei Techniken entwickelt, die ksh scope "brechen", um mehr wie ksh88/bash/mksh/zsh usw. zu sein.

Das erste funktioniert in nicht gebrochenen POSIX-Shells.

#!/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" 

Die zweite Methode funktioniert nur in KSH artigen Schalen und beinhaltet explizit alles durch Bezugnahme vorbei und ausgiebig mit indirection.

#!/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 

ich entweder von diesen nur empfehlen, wenn Sie einer der wenigen sind, die robuste Bibliothek Code erfordert das Schreiben, die zu tragbar sein muss.

+0

Hallo Ormaaj, vielen Dank für Ihre ausführliche und sehr hilfreiche Antwort. Es scheint so, als hätte ich falsche Erwartungen und mehr zu tun, als ich mir erhofft hatte. Aber jetzt weiß ich zumindest, wie es mit den kommenden Problemen im Migrationsprozess weitergeht. – Cologne2202

Verwandte Themen