typeset in ksh93 não funciona como esperado

5

Eu achei que typeset era ksh local , mas isso falha em ksh93 embora funcione em todas as minhas outras conchas typeset -supporting (bash, yash, zsh, pdksh)

#!/bin/ksh -ex

foo(){
    typeset a b
    a=0; b=1
    return
}
a=a; b=b
foo
#confirm that the globals didn't change
[ "$a" = a ] 
[ "$b" = b ]

O que dá?

    
por PSkocik 04.07.2017 / 11:23

1 resposta

9

typeset é private do ksh93 (usando escopo estático como perl ' my , não local que faz escopo dinâmico) somente para funções que são declaradas usando o estilo de definição da função ksh:

function foo {
  typeset var=whatever
  ...
}

Com a sintaxe Bourne (ou com o comando . (que também pode ser usado em funções no estilo ksh)), não há escopo (exceto $1 , $2 ... $# claro). Portanto, é possível usar as funções do estilo Bourne para obter o valor ou alterar o valor ou o tipo de uma variável no contexto pai (embora typeset -n também possa ser usado para isso com o estilo ksh.

Em ksh88, typeset estava fazendo o escopo dinâmico com o estilo de definição de função ksh e Bourne. De acordo com David Korn, POSIX não especificou o escopo variável do ksh com base em que ele era dinâmico (considerado inferior) e é por isso que ele mudou para escopo estático para ksh93 (uma reescrita completa). / p>

Mas nesse meio tempo, outros shells implementaram o escopo de variáveis e todos eles fizeram isso usando o escopo dynamic para imitar o ksh88.

zsh agora tem uma palavra-chave private para ter escopo semelhante a ksh93 além de local / typeset com escopo dinâmico como em ksh88 .

Para ver a diferença entre o escopo estático e o dinâmico, compare:

"$shell" -c 'function f { typeset a=1; g; echo "$a"; }
             function g { echo "$a"; a=2; }
             a=0; f'

Com $shell == ksh93 saídas:

0
1

E com ksh88 ou bash de saídas:

1
2

zsh :

$ zsh -c 'zmodload zsh/param/private
          f() { private a=1; g; echo $a;}
          g() { echo $a; a=2; }
          a=0; f'
0
1

Para poder usar o escopo local no código portátil para bash , zsh , ksh88 ksh93 , pdksh , yash ou dash / FreeBSD sh, você poderia fazer:

[ -n "$BASH_VERSION" ] && shopt -s expand_aliases
alias shdef= kshdef='#'
if type typeset > /dev/null 2>&1; then
  alias mylocal=typeset
  if (a=1; f() { typeset a=2; }; f; [ "$a" = 2 ]); then
    alias shdef='#' kshdef='function'
  fi
else
  alias mylocal=local
fi

Em seguida, declare suas funções como:

kshdef foo
shdef foo()
{
  mylocal var
  var=value
  ...
}

Em qualquer caso, existem muitas diferenças entre o comportamento daqueles local nos vários shells. Além da consideração dinâmica vs estática mencionada acima, há se as variáveis inicialmente obtêm um valor não definido ou vazio ou herdam o valor do escopo pai. E há a interação com readonly , unset , se local / typeset é uma palavra-chave ou interna (afeta o gerenciamento split + glob) ...

Existem outras implicações de usar a definição da função ksh-style em ksh93 , veja a página man para detalhes.

Veja link para o esforço POSIX de padronizar o escopo local em sh .

    
por 04.07.2017 / 11:31