Как предотвратить перезапись KSH в Linux глобальной переменной локальной переменной?

Я участвую в процессе переноса системы, содержащей несколько сценариев 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 

мои вопросы:

  • есть ли переменная среды, которую я могу установить, чтобы заставить KSH Linux вести себя как на AIX? Недостаток что:
  • есть ли опция на KSH Linux, чтобы получить требуемое поведение? Если это:
  • какие изменения в коде я должен сделать, чтобы получить желаемое поведение в Linux?

Примечание:

  • Я уже пытался объявить переменную с "local", но это вернуло ошибку в Linux, на AIX она работает.

следующая таблица суммирует две системы:

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)

1 ответов


TL; DR: для тривиальных случаев: переключите синтаксис определения функции из f() compound-command to function f { ...; }. Для сложных случаев: зависите от ksh93-only (гораздо более гибкий), используйте ниже абсурдные хаки (жесткий), перепишите строго POSIX (возможно, жесткий, негибкий), перепишите на реальном языке (но оболочки иногда хороши).

нет "Linux ksh". Он ведет себя одинаково во всех системах и зависит только от используемой версии.

AIX корабли a изменен ksh88. у ksh88 была динамическая система прицела, похожая на Bash и все другие оболочки, которые поддерживают местных жителей, но в отличие от ksh93. Для того, чтобы местные жители работали под ksh93, вы должны использовать "современный"function name { ; } синтаксис, а не синтаксис POSIX для определения функций. Это может потребоваться или не потребоваться в ksh88, так как это не документировано, и для меня нет возможности протестировать, поскольку ksh88 является проприетарным программным обеспечением и, скорее всего, даже не построен для работы на современном оборудовании x86.

если выше правильно, и ваши скрипты были написаны для ksh88, достаточно просто переключить синтаксис определения функции, чтобы локальные переменные хотя бы функционировали. Однако, в то время как статическая область ksh93 значительно превосходит динамическую область других оболочек, это вызывает серьезную проблему переносимости-вероятно, одну из самых сложных для работы во всех сценариях оболочки.

Если вам нужны портативные местные жители, нет никаких фантастических решений. Я придумал две техники, которые "ломают" ksh объем, котор нужно быть больше как ksh88/bash/mksh / zsh etc.

первый работает в не сломанных оболочках 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"

второй метод работает только в 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}
    typeset y=yojo

    # mksh... you fail at printf. We'll try our best anyway.
    eval "$(printf %${is_mksh+.s%s=%s%.s }s=%q  "" ${is_mksh+"${y@Q}"} "$y")"
}


f

я рекомендую только один из них, если вы один из немногих, который требует написания надежного кода библиотеки, который также должен быть портативным.