2013-03-28 5 views
7

Sono coinvolto nel processo di porting di un sistema contenente diversi script ksh da AIX 6.1 a SUSE-Linux. Ho incontrato il seguente differenza nel modo in ksh si comporta sui due sistemi:Come impedire a ksh su Linux di sovrascrivere un varibale globale con una variabile locale?

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

Il risultato corretto su AIX è:

var = globalvariable 
var = localvariable 
var = globalvariable 

Il risultato sbagliato su Linux è:

var = globalvariable 
var = localvariable 
var = localvariable 

Le mie domande sono:

  • Is c'è una variabile di ambiente che posso impostare per far sì che il ksh di Linux si comporti come su AIX? In caso contrario:
  • Esiste un'opzione su Ksh di Linux per ottenere il comportamento richiesto? In caso contrario:
  • Quali modifiche nel codice devo fare per ottenere il comportamento desiderato su Linux?

Nota:

  • ho già provato a dichiarare la variabile con "locale", ma che ha restituito un errore su Linux, su AIX funziona.

La tabella seguente riassume i due sistemi:

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) 

risposta

4

TL; DR: Per i casi banali: accendere la sintassi definizione della funzione f() compound-command-function f { ...; }. Per i casi complessi: dipende da ksh93-only (molto più flessibile), usa i seguenti assurdi hack (hard), riscritto per essere rigorosamente POSIX conforme (forse difficile, inflessibile), riscrivere in un linguaggio reale (ma le shell a volte sono belle).

Non c'è "Linux ksh". Si comporta allo stesso modo su tutti i sistemi e dipende solo dalla versione che stai utilizzando.

AIX invia un ksh88 modificato. ksh88 aveva un sistema di scope dinamico, simile a Bash e tutte le altre shell che supportano i locali, ma a differenza di ksh93. Affinché la gente del posto possa lavorare sotto ksh93, è necessario utilizzare la sintassi "moderna" function name { ; }, anziché la sintassi POSIX per definire le funzioni. Questo può essere o non essere richiesto in ksh88, in quanto non è documentato e non c'è modo per me di testare, dato che ksh88 è un software proprietario e molto probabilmente non è nemmeno costruito per funzionare su hardware x86 moderno.

Se quanto sopra è corretto, e i vostri script sono stati scritti per ksh88, semplicemente passare sintassi definizione di funzione è sufficiente per le variabili locali ad almeno la funzione. Tuttavia, sebbene lo scope statico di ksh93 sia di gran lunga superiore all'ambito dinamico di altre shell, causa un serio problema di portabilità, probabilmente uno dei più difficili da risolvere in tutti gli script di shell.

Se avete bisogno di locali portatili, non ci sono soluzioni fantastiche. Mi è venuta in mente due tecniche che "break" scope ksh essere più come ksh88/bash/mksh/zsh ecc

Le prime opere in gusci non-rotto 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" 

Il secondo metodo funziona solo in gusci ksh-like e coinvolge passando esplicitamente tutto per riferimento e utilizzando indiretto ampiamente.

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

vi consiglio solo uno di questi se sei uno dei pochi che richiede la scrittura di codice robusto libreria che deve essere troppo portatile.

+0

Ciao Ormaaj, la ringrazio molto per la tua risposta dettagliata e MOLTO utile. Sembra che avessi aspettative false e altro da fare di quanto speravo. Ma ora so come procedere nei prossimi problemi nel processo di migrazione. – Cologne2202

Problemi correlati