Variáveis de acesso definidas dentro de substituições de comandos

4

Eu escrevi um script simples

 #!/bin/bash -x
 selentry='ls -l / | sort ; ts=${PIPESTATUS[0]}'
 echo $ts

mas $ ts não mostram nada. Como posso exibir a variável $ ts ou como posso obter o código de status de saída do comando na variável?

selentry='ls -l / | sort'
    
por DeadKenny 25.01.2017 / 14:42

1 resposta

4

Em:

selentry='ls -l / | sort ; ts=${PIPESTATUS[0]}'

o mesmo que o mais moderno:

selentry=$(ls -l / | sort ; ts=${PIPESTATUS[0]})

O código dentro do $(...) é executado em um ambiente subshell (no caso de bash e shells diferentes de ksh93 , ele é executado em um processo de shell diferente). Portanto, qualquer modificação feita nas variáveis dessa subcamada não afetará o shell pai.

Quando você faz:

var=$(cmd)

No entanto, o status de saída de cmd é disponibilizado em $? . Isso não se estende a $PIPESTATUS , que no caso de:

var=$(foo | bar)

contém apenas um valor (o código de saída do subshell que aqui seria o status de saída de bar (a menos que a opção pipefail esteja ativada, caso em que pode ser o status de saída de foo se não for -zero). É ainda pior em zsh , onde a matriz $pipestatus não é afetada pelos comandos de atribuição.

Aqui, porém, se você não se importa com o status de saída de sort (do subshell), você pode fazer:

selentry=$(ls -l / | sort; exit "${PIPESTATUS[0]}")
ts=$?

Aqui, você também pode fazer:

exec 3< <(ls -l /) # here ls is started as an asynchronous command
ls_pid=$!
selentry=$(sort <&3)
sort_status=$?
wait "$ls_pid"
exec 3<&- # close that fd 3
ls_status=$?

Ou até mesmo:

{
  selentry=$(sort)
  sort_status=$?
  wait "$!"
  ls_status=$?
} < <(ls -l /)

Na questão mais geral de que as substituições de atribuições de variáveis sobrevivem a substituições de comandos, em ksh93 , é possível usar a forma ${ cmd;} de substituição de comando ( ksh93 não suporta $PIPESTATUS / $pipestatus ).

var=${
  foo; c1=$?
  bar; c2=$?
}

Não há equivalente em outros shells semelhantes a Bourne, você precisaria passar os dados por meio de outro meio, como um arquivo temporário:

var=$(
  foo; echo "c1=$?" > "$tempfile"
  bar; echo "c2=$?" >> "$tempfile"
)
. "$tempfile"

Ou aqui:

selentry=$(
  ls -l / | sort
  typeset -p PIPESTATUS | sed '1s/PIPESTATUS/my_&/' > "$tempfile"
}
. "$tempfile"
ls_status=${my_PIPESTATUS[0]}
    
por 25.01.2017 / 15:26