Avaliação de backticks no bash

2

Estou confuso sobre a avaliação de backticks no bash. Eu já vi código assim antes, o que faz sentido:

RESULT='whoami'

Isso armazena a saída do comando whoami na variável RESULT e confirma que os backticks são avaliados na saída do comando dentro deles. Mas também vi código como o seguinte:

if 'wget google.com -T 2 -t 1 -o /dev/null'; then 
   echo "Internet ok"
fi

Isso está testando a conectividade com a Internet, tentando obter a página inicial do Google (com -t 1 para uma única tentativa, -T 2 para um tempo limite de 2 segundos e um redirecionamento para /dev/null , pois não quer a saída, em vez disso, só quer ver se é bem-sucedida). O código lê como se o autor estivesse esperando que os backticks avaliassem o código de saída do comando wget em vez da saída.

Mas na verdade funciona. Ele imprime Internet ok se conseguir se conectar ao google.com e, se eu alterar o URL para algum URL sem sentido que não exista, ele não satisfaz a declaração if e não imprime nada. Eu não entendo porque isso funciona.

A execução independente do comando wget com URLs válidos e inválidos não imprime nada nos dois casos e só é diferente pelo código de saída.

Minha conclusão é que existe uma construção especial para if seguida de backticks que retorna o código de saída em vez da saída. Estou errado?

    
por Marplesoft 08.02.2017 / 20:38

3 respostas

5

Não, os backticks não têm um significado especial e você pode executar o comando wget sem eles na instrução if .
if sempre avalia o código de saída do comando seguido.

Uma visão geral mais abrangente pode ser encontrada aqui .

EDITAR

Backticks iniciam uma substituição de comando que é executada em uma subshell e retorna um código de saída. if apenas verifica os códigos de retorno, ele não faz uso da saída do comando.

Para comparar a saída de um comando, você pode usar o [ , que deve ser fechado com ] , que basicamente é um teste. O teste pode ser qualquer coisa

  • de man test
  • uma comparação de string

    [ "hello" == "test" ]
    
  • um teste inteiro

    [ 2 -eq 3 ]  
    

Se o teste for bem-sucedido, você receberá um código de saída 0 (verdadeiro); caso contrário, não será 0 (falso), o que é novamente avaliado por if .

Então você tem algo em mente como segue.

if [ "'wget google.com -T 2 -t 1 -o /dev/null'" == "" ]
then 
    echo "emptY"
fi

Mas isso não faria muito sentido, pois o redirecionamento da saída para /dev/null sempre será real de [ " wget google.com -T2 -t1 -o / dev / null " == "" ] .
Por outro lado, também não seria útil verificar se a saída do comando wget contém saída, deixando de fora o -o /dev/null , porque mesmo em uma situação de erro, você obterá a saída, mas códigos de retorno diferentes.

    
por 08.02.2017 / 20:55
1

No bash if shell scripting, evite backticks nos dias de hoje e use a substituição do comando $(...) syntax.

É mais claro do que os backticks muito vagos e suporta o aninhamento, algo que não é possível nos backtics. I.E:

command $(command two $(command three))
    
por 08.02.2017 / 21:53
0

Eu finalmente consegui uma resposta clara para isso através de um tópico de discussão na lista de discussão do bash. A conclusão é a seguinte:

  • Não há nada especial sobre a declaração if aqui, ela está simplesmente executando o comando após o if e depois ramificando com base no código de saída desse comando. O comportamento inesperado aqui é atribuído à própria substituição do comando.
  • Um comando backticked (substituição de comando) sempre avalia a saída do comando dentro deles, não o código de saída (isso não é novidade, apenas confirmando se os backticks são usados em um if ou não é irrelevante).
  • Com base nos dois pontos acima, a razão óbvia é que if 'cmd' ... executa o if body com base no código de saída de cmd quando cmd escreve nada para stdout é que existe uma regra de especificação POSIX sobre a execução do comando shell que diz:

If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed. Otherwise, the command shall complete with a zero exit status.

ref: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

  • Portanto, só porque no caso em que cmd não escreve nada no stdout, o shell - em vez de executar um comando vazio - pega o código de saída da substituição do comando (o código de saída do cmd ) e retorna esse como o código de saída do comando pai - que então sobe para o if .

Para ilustrar melhor isso, veja o seguinte exemplo:

$ 'true'
$ echo $?
0
$ 'false'
$ echo $?
1

O shell primeiro executa true , que não emite nada para stdout, portanto, o comando resultante está vazio. Onde eu esperava que um comando vazio tivesse sucesso ou falha deterministicamente, com base na regra acima, ele é concluído com o código de saída de true em vez de "o código de saída de um comando vazio".

    
por 08.03.2017 / 20:43

Tags