2013-03-28 14 views
7

Jestem zaangażowany w proces przenoszenia systemu zawierającego kilka skryptów ksh z AIX 6.1 do SUSE-Linux. Mam natknąć się następującą różnicą w sposób ksh zachowuje się na dwóch systemach:Jak zabezpieczyć ksh w systemie Linux przed nadpisaniem globalnego varibale przez zmienną lokalną?

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

Prawidłowy wynik na AIX jest:

var = globalvariable 
var = localvariable 
var = globalvariable 

niewłaściwy wynik na Linux jest:

var = globalvariable 
var = localvariable 
var = localvariable 

Moje pytania są następujące:

  • istnieje zmienna środowiskowa, którą mogę ustawić, aby ksh Linuksa zachowywał się jak w systemie AIX? W przeciwnym razie:
  • Czy istnieje opcja na ksh w Linuksie, aby uzyskać wymagane zachowanie? W przeciwnym razie:
  • Jakie zmiany w kodzie mam zrobić, aby uzyskać pożądane zachowanie w systemie Linux?

Uwaga:

  • Próbowałem już zadeklarować zmienną „lokalny”, ale wystąpił błąd w systemie Linux, AIX działa.

Poniższa tabela podsumowuje dwa systemy:

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) 

Odpowiedz

4

TL; DR: Dla błahych sprawach: przełączyć składnię definicji funkcji z f() compound-command do function f { ...; }. W przypadku złożonych przypadków: polegaj tylko na ksh93 (o wiele bardziej elastycznym), użyj poniższych absurdalnych hacków (twardych), przepisz, aby być ściśle zgodnym z POSIX (może twardym, nieelastycznym), przepisuj w prawdziwym języku (ale muszle są czasami miłe).

Nie ma "Linux ksh". Zachowuje się tak samo na wszystkich systemach i zależy tylko od wersji, z której korzystasz.

System AIX wysyła zmodyfikowaną wersję ksh88. ksh88 miał dynamiczny system zakresów, podobny do Basha i wszystkich innych powłok, które obsługują locals, ale w przeciwieństwie do ksh93. Aby locals działało pod ksh93, musisz użyć składni "nowoczesnej" function name { ; }, a nie składni POSIX do definiowania funkcji. To może, ale nie musi być wymagane w ksh88, ponieważ nie jest ono udokumentowane i nie ma możliwości przetestowania go, ponieważ ksh88 jest prawnie zastrzeżonym oprogramowaniem i najprawdopodobniej nie jest zbudowany na nowoczesnym sprzęcie x86.

Jeśli powyższe jest poprawne, a twoje skrypty zostały napisane dla ksh88, wystarczy zmienić składnię definicji funkcji, aby przynajmniej funkcjonowały zmienne lokalne. Chociaż zakres statyczny ksh93 jest znacznie lepszy od zakresu dynamicznego innych powłok, powoduje to poważny problem przenośności - prawdopodobnie jeden z najtrudniejszych do obejścia we wszystkich skryptach powłoki.

Jeśli potrzebujesz przenośnych mieszkańców, nie ma fantastycznych rozwiązań. Wymyśliłem dwie techniki, które "łamią" zakres ksh, aby były bardziej podobne do ksh88/bash/mksh/zsh itd.

Pierwsze prace w niezłamanych powłokach 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" 

Druga metoda działa tylko w powłokach przypominających ksh i polega jawnie na przekazywaniu wszystkiego przez odniesienie i intensywne używanie kierunku pośredniego.

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

Polecam tylko jedno z nich, jeśli jesteś jednym z niewielu, który wymaga napisania solidnego kodu biblioteki, który również musi być przenośny.

+0

Witaj Ormaaj, dziękuję bardzo za szczegółową i BARDZO pomocną odpowiedź. Wydaje się, że miałem fałszywe oczekiwania i więcej do zrobienia, niż miałem nadzieję. Ale teraz wiem przynajmniej, jak postępować w nadchodzących problemach w procesie migracji. – Cologne2202

Powiązane problemy