Qual é a diferença entre 'test' e avaliando com / dev / null?

3

Eu notei diferentes scripts .sh para homebrew que verificam se ele está instalado.

Um usa essa sintaxe:

if test ! $(which brew); then

O outro usa essa sintaxe:

if ! which brew > /dev/null; then

Eu entendo que ambos estão verificando o código de saída para which brew , mas estou curioso para saber se existem outras diferenças entre eles. Para mim, o primeiro é mais claro e eu diria (talvez incorretamente) mais eficiente, já que ele não precisa redirecionar nenhuma saída.

Além disso, por que o segundo realmente executa which brew , independentemente de a saída ser enviada para /dev/null ou não? Apenas como funciona o shell?

    
por runofthemill 16.04.2016 / 09:13

2 respostas

3

O primeiro é um hack desajeitado, o segundo é um erro comum.

Esses dois testes fazem algo completamente diferente, o que produz o mesmo resultado.

if test ! $(which brew); then

Isso testa se a saída de which brew está vazia.

  • Se brew estiver no caminho de pesquisa, então which brew produzirá uma palavra de saída, portanto, o comando test receberá dois argumentos: ! e o caminho para brew . Quando test tiver dois argumentos, o primeiro dos quais é ! , retornará verdadeiro se o segundo argumento estiver vazio (o que não é o caso aqui) e, caso contrário, será falso.
  • Se brew não estiver no caminho de pesquisa, a saída de which brew estará vazia, portanto, o comando test receberá um único argumento que é ! , portanto test retornará verdadeiro.

Observe que esse comando produzirá uma mensagem de erro e um status de falha se o caminho para brew contiver espaço em branco, porque é o que significa uma substituição de comando sem aspas . Acontece que um status de falha era o resultado desejado aqui, então isso funciona de maneira indireta.

Este comando não testa o código de saída de which brew . O código de saída é ignorado.

if ! which brew > /dev/null; then

Esta é a maneira direta de testar se which brew é bem-sucedido. Não depende de nada frágil, exceto which em si.

which brew é sempre chamado em ambos os casos. Por que seria importante que a saída fosse redirecionada para /dev/null ? "Ocultar a saída deste comando" não significa "não executar este comando".

A maneira correta de testar se brew não está disponível no caminho de pesquisa do comando é

if ! type brew >/dev/null 2>/dev/null; then

Veja Por que não usar "which"? O que usar então?

    
por 17.04.2016 / 00:11
1

Parte 1 if test ! $(which brew); then ...

  1. Se você executar which brew , seu $PATH será pesquisado por um executável chamado brew . Se um for encontrado, o nome será impresso para stdout. Se nada for encontrado, uma mensagem de erro será impressa em stderr. (Alguns shells fornecem um which embutido que também reporta funções embutidas e shell, palavras reservadas, .... Por exemplo zsh .)
  2. $(...) captura o stdout (mas não o stderr) de qualquer que seja o ... shellcommands e o coloca na linha de comando como argumento (s).
  3. test ! ... retorna o código de retorno invertido de test ... . Essa é a maneira de test de negar uma expressão. test ... (sem nenhuma opção na parte ... ) apenas testa se a parte ... não é a sequência vazia.

Resultado : which é usado para procurar um executável chamado brew . O caminho resultante ou uma string vazia é colocada na linha de comando como um argumento para test ! , que verifica se esse argumento é a string vazia e, portanto, retorna 0 (true).

Parte dois if ! which brew > /dev/null; then ...

Aqui which brew é o mesmo que acima. Se which encontrar um executável, ele não apenas imprime o nome, mas também retorna com o código 0 (true). Se não encontrar nada, imprime uma mensagem de erro e retorna algum outro código (falso). Este código é invertido pelo shell por causa do ! na frente do comando ( 0 - > 1 , qualquer outra coisa - > 0 ). É com isso que if se preocupa. Como o usuário não se importa em ver o caminho real de brew , a saída padrão de which é redirecionada para /dev/null .

Notas:

Em ambos os casos, o stderr de which não é redirecionado e deve ser visível no terminal.

Eu não testei, mas presumo que o segundo formulário seja mais rápido, já que ele inicia apenas um processo / builtin. Mas ambos os comandos fazem o redirecionamento: O segundo explicitamente para /dev/null , o primeiro menos óbvio (a princípio) capturando a saída de which com $(...) . Você pode comparar a velocidade com algo como a função comp que eu uso . / p>

Existem páginas man para which e test . E a página man do shell ( sh , ksh , bash , zsh ) tem uma seção sobre redirecionamento e substituição de comando, bem como em builtins (não apenas which mas também test is muitas vezes implementado como um builtin).

    
por 16.04.2016 / 09:42