Bash scripting - valor de retorno 'type' diferente no script de inicialização

1

Alguém por favor pode me explicar isso:

$ type blah
bash: type: blah: not found
$ echo $?
1

$ bash --init-file <( echo "type blah; echo $?" )
bash: type: blah: not found
0

Por que o valor de retorno é diferente em um script de inicialização do que em um shell interativo?

Editar E diferente novamente no script de inicialização de um shell interativo:

$ bash --init-file <( echo "type blah; echo $?" ) -i
bash: type: blah: not found
2

Versão do Bash é 4.4.12.

    
por Tom 17.11.2017 / 17:01

2 respostas

1

O problema é que $? está sendo avaliado antes que é passado como um argumento para o comando echo externo. Como resultado, você está executando o equivalente a:

bash --init-file <( echo "type blah; echo 0" ) -i

Você pode ver isso usando o modo set -x , que mostrará o equivalente dos comandos executados:

$ bash --init-file <( echo "type blah; echo $?" )
+ bash --init-file /dev/fd/63
++ echo 'type blah; echo 0'
bash: type: blah: not found
0

Observe a terceira linha, ++ echo 'type blah; echo 0' - o $? já foi expandido antes de ser passado para o comando echo (e daí para o novo shell a ser executado). BTW, isso significa que ele está realmente mostrando o resultado do último comando executado antes deste:

$ curl http://notarealdomain.example.com/
curl: (6) Could not resolve host: notarealdomain.example.com
$ bash --init-file <( echo "type blah; echo $?" )
bash: type: blah: not found
6

Observe que o status impresso, "6", é o código de curl para um erro de host não resolvido.

De qualquer forma, a solução é simples: use aspas simples para atrasar a avaliação do $? :

$ bash --init-file <( echo 'type blah; echo $?' )
bash: type: blah: not found
1
    
por 18.11.2017 / 20:46
1

Responda primeiro

  1. O script init não tem nada a ver com o valor de retorno.
  2. A substituição do processo <(...) é a causa real.

Explicação

[Proof1] Agora, tente este comando abaixo. Não tem opção --init-file , mas a mesma saída (com algumas impressões triviais).

(exit 10)
bash <( echo "type blah; echo $?" )

[Proof2] Tente seguir os comandos e altere o número no primeiro, você encontrará um valor de retorno diferente.

(exit 117)
bash --init-file <( echo "type blah; echo $?" )

[Proof3] Qual saída você vê?

(exit 23)
cat <( echo "type blah; echo $?" )

Eu acho que você pode entender a Answer1 através das 3 provas acima. E quanto a Answer2?

Se você apenas digitar o comando simples echo "type blah; echo $?" para executá-lo, qual resultado você espera? Você espera que ele imprima type blah; echo <num> , dos quais <num> é o valor de retorno do último comando. Certo? Nós todos sabemos que o $? será substituído por um número, porque todos sabemos que o bash executará a expansão dos parâmetros em $? .

É o mesmo em processo de substituição <(...) .

No Bash, os comandos que aparecem em uma substituição de processo <(...) serão invocados em um subshell. Subshell também é um shell (Bash). Assim, para o comando echo "type blah; echo $?" , você obterá exatamente o mesmo resultado em subshell que você executará diretamente no shell atual, o que significa que o subshell também executará a expansão de parâmetro em $? , da mesma forma que um bash faz.

Portanto, quando você estiver executando bash --init-file <(echo "type blah; echo $?") , o conteúdo do arquivo de script init será realmente type blah; echo <num> , em vez de type blah; echo $? .

Mais profundo

Embora na substituição de processo <(echo "type blah; echo $?") o $? seja expandido por subshell, seu valor é afetado pelo shell atual. O valor de ? na subshell é o mesmo que o da shell atual.

Veja o Proof2, o primeiro comando é (exit 117) , o que faz com que o valor de $? no shell atual seja 117. Mas ele é expandido para 117 em subshell também.

Isso ocorre porque os comandos que aparecem na substituição de processo <(...) são invocados em um ambiente de subshell que é uma duplicata do ambiente de shell atual.

Então, isso explica em sua pergunta que você mostrou um valor de retorno diferente se colocar a opção -i no comando. Essa não é a diferença trazida pela opção -i . Isso porque antes desse comando, você definitivamente executa outro comando que retorna 2.

Mais palavras

Na verdade, existem três outras formas trabalhando da mesma maneira que a substituição de processos no bash.

  1. Substituição de comando $(...) ou '...'
  2. Comandos agrupados com parênteses (...)
  3. Comandos incorporados no pipeline <builtin cmd> | ... ou ... | <builtin cmd> ou <builtin cmd> | <builtin cmd>
por 19.11.2017 / 11:48

Tags