Existe uma maneira menos complicada de definir o array $ path localmente dentro da função?

5

Existe uma maneira menos trabalhosa de definir uma versão local do array $path do que é mostrado no snippet a seguir?

foo () {
    local holdpath
    holdpath=($path)
    local path
    path=($holdpath)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

Estou me referindo especificamente à música e dança com holdpath ...

Se, em vez disso, eu definir

foo () {
    local path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

... a primeira atribuição a path aciona um erro bad pattern . Claro, se em vez disso eu definir

foo () {
    local path
    path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

... a primeira atribuição a path não faz diferença (isto é, pode ser omitida sem alterar os resultados); com ou sem ele, $path estará vazio.

EDITAR:

O script a seguir testa as várias sugestões que recebi até agora:

foo_0 () {
  echo ${#path}
  local PATH=$PATH
  echo ${#path}
}

foo_1 () {
  echo ${#path}
  eval "local path; path=(${(q)path})"
  echo ${#path}
}

foo_2 () {
  echo ${#path}
  eval "$(local -p path)"
  echo ${#path}
}

for i ( 0 1 2 ) {
  fn=foo_$i
  echo "# $fn"
  $fn
  echo
}

A saída é:

# foo_0
22
22

# foo_1
22
1

# foo_2
22
22

Assim, as saídas para foo_0 e foo_2 são pelo menos consistentes com o que estou tentando alcançar. Algo não está funcionando com foo_1 como dado acima, mas eu me livrei do (q) na atribuição para path , ou seja,

foo_1 () {
  echo ${#path}
  eval "local path; path=($path)"
  echo ${#path}
}

... então a saída concorda com a de foo_0 e foo_2 . Infelizmente, mesmo depois de ler a documentação do qualificador q algumas vezes, não entendo muito bem o que é suposto fazer na receita original.

Além disso, não consigo entender por que a seguinte variante da linha de comando de foo_0 difere da acima:

% (foo_0a () { echo ${#path}; local PATH=$PATH; echo ${#path} }; foo_0a)
22
1

FWIW, as variantes de linha de comando correspondentes de foo_1 e foo_2 produzem os mesmos resultados que seus originais no script:

% (foo_1a () { echo ${#path}; eval "local path; path=(${(q)path})"; echo ${#path} }; foo_1a)
22
1
% (foo_2a () { echo ${#path}; eval "$(local -p path)"; echo ${#path}; }; foo_2a)
22
22

Além disso, em todos os casos acima em que echo ${#path} produz 1 em vez de 22 , a razão é que a variável $path local contém todos os caminhos individuais em uma única sequência, separados por espaços.

    
por kjo 26.06.2013 / 18:03

2 respostas

3

Enquanto para arrays tied , você pode usar a resposta do rici , no geral caso, você poderia fazer:

foo() {
  eval "local array; array=(${(q)array[@]})"
  ...
}

O (q) é para citar os elementos das matrizes. Por exemplo, para um valor de $PATH como /foo bar:/x$y , "${(q)path[@]}" expandiria para /foo\ bar /x\$y . Precisamos escapar desses caracteres space e dollar porque essa string é passada para eval .

Você também pode fazer:

foo() {
  eval "$(local -p array)"
  ...
}

que funcionaria com qualquer tipo de variável, mas que cria um processo extra.

    
por 26.06.2013 / 19:38
5

Use o formato escalar PATH em vez do array path . Tornar qualquer um desses locais efetivamente torna ambos locais, então:

foo() {
  local PATH=$PATH
  if ( some_condition ) path=( $PREFIX $path )

  # do stuff
}

(Observe que isso não funcionará se algum componente do caminho tiver um : incorporado).

Infelizmente, não é possível inicializar um parâmetro de matriz local em uma instrução, tornando impossível inicializar um parâmetro de matriz local usando seu valor original.

    
por 26.06.2013 / 18:40