Existe uma diferença entre os '&&' e ';' símbolos em um terminal BASH padrão?

56

Eles parecem sinalizar para o BASH começar com outro comando após os símbolos, mas há uma diferença distinta?

Michael Terry
fonte

Respostas:

75

Com esta linha:

command1 && command2

command2 será executado se (e somente se) command1 retornar o status de saída zero, enquanto nesta linha:

command1 ; command2

comando1 e comando2 serão executados independentemente. O ponto e vírgula permite que você digite muitos comandos em uma linha.


fonte
11
Interessante! Eu pensei que poderia ser apenas uma maneira mais confortável. Obrigado!
42

Você pode tentar a diferença por si mesmo:

  1. ls /invalid/path && echo "hello!"
    como / invalid / path não existe, não é possível mostrar a listagem do diretório. Ele falhará com uma mensagem de erro: "ls: / invalid / path: Esse arquivo ou diretório não existe".
    A segunda metade do comando (eco "olá!") Nunca é executada porque a primeira metade falhou.

  2. ls /invalid/path ; echo "hello!"
    A mesma mensagem de erro aparece como antes, mas desta vez, a segunda parte é executada !
    ls: / invalid / path: Não existe esse arquivo ou diretório
    Olá!

Por que isso é útil?
Suponha que você deseja extrair um arquivo chamado archive.tar.gz
Você pode usar o comando tar zxvf archive.tar.gz && rm archive.tar.gz.
Se, por algum motivo, a extração do arquivo falhar, a segunda parte não será executada! Você pode tentar novamente.

Se você usar ; na mesma situação, o arquivo é excluído e você não pode tentar novamente.

Kenny Rasschaert
fonte
8

&&é AND, o que significa que o segundo comando será executado apenas se o primeiro retornar verdadeiro (sem erros).

Ward Muylaert
fonte
11
&& é um "depois" (não um "e") ... ver a minha resposta
Peter.O
2
@fred Eu diria que é um "e" com avaliação de curto-circuito - se a primeira parte não for verdadeira, ela sabe que o resultado total deve ser falso, e ignora a segunda parte. Mas concorde que pensar nisso como um "então" raramente faz muita diferença nesse contexto.
jg-Fausto
2
@fred Embora conceitualmente possa ser mais fácil entendê-lo dessa maneira, eu discordo de sua declaração. A idéia é simplesmente que, com qualquer AND execução, o segundo parâmetro se torne irrelevante se o primeiro for igual falsee, portanto, o código subjacente seja otimizado para adiar a avaliação do segundo parâmetro até que ele saiba qual é o primeiro.
Ward Muylaert
2
@ fred Não sei ao certo qual ponto esse exemplo está tentando mostrar. &&é apenas um operador binário, uma função. A única coisa "especial" é que é a notação de infixo (que é padrão para a maioria desses tipos de operadores) e a execução atrasada do segundo operando. Essa execução atrasada realmente oferece a capacidade de ser usada como algo que pode ser conceitualmente visto como uma ifdeclaração nesse contexto , mas isso não tira o fato de que o uso originalmente pretendido está dentro do condicional de uma ifdeclaração real . O uso aqui realmente é mais um "hack".
Ward Muylaert
3
@fred Claro que não é um operador ternário, é apenas a sucessão de duas operações a && b || c = (a && b) || c. Ordem simples de avaliação. Não há realmente nenhum mistério lá. Se você os escrever como suas funções típicas, seria simplesmente parecido or(and(a, b), c). Essa lógica é a mesma tanto dentro de uma ifcondicional quanto na entrada direta na linha de comando, porque &&e ||como operadores , eles pegam dois operandos e retornam outro.
Ward Muylaert
8

Atualização : eu adicionei como script para destacar algumas das possíveis armadilhas:

Como ninguém mais mencionou "||", eu irei

Atualização2 : algumas reformulações importantes aqui
&& são como um "então" de uma declaração "se" que responde a "verdadeiro"

|| NÃO é como o "else" de uma declaração "if" ..
|| é como um "então" de uma declaração "se" que responde a "falso"

Mais especificamente, && testa o $? retorna o valor da instrução executada mais recentemente anterior e passa o controle para a instrução ou sub-shell imediatamente após o && ... ele somente passa o controle se $? é verdade.

|| é semelhante e geralmente é visto após uma instrução &&, mas testa um valor de retorno falso ($?) da instrução executada mais recentemente anterior ... NB! Nota Bene! Observe bem! .... se a instrução precedente for uma instrução && que retrocede falso quando você espera que seja verdadeira, então || responderá ao falso, portanto, misturar os dois na mesma linha pode ser arriscado

O ponto principal que estou tentando cometer é em relação a um erro que cometi. ou seja:
## [[condição]] && A || B
is not não se comporta como um ternário de estilo C / C ++. ou seja:
// (condição)? A: B
Veja o script abaixo para exemplos de resultados "inesperados" de "A"

O teste básico e os && e os || A instrução deve estar na mesma linha ...


Execute este script para ver onde as coisas podem dar errado ao usar && e ||
A instrução executada mais recentemente pode não ser a que você espera.

[[condição]] && eco Olá || eco Adeus .... normalmente é seguro,
pois um eco bem formado retornará verdadeiro.
mas e quanto a acessar um arquivo que não sai?

#!/bin/bash
#
# "as expected" return codes" means: expected to behave like a normal AND / OR  contition test
#
if [[ "$1" != "" ]] ; then exit $1; fi # recursive call to return an arbitary $? value (decimal)
echo
echo 'test 1: All return codes are "as expected"'
echo  ======
 ((1==1)) && echo  " ((1==1)) rc=$? ..&&.. condition is true" || echo  " ((1==1)) rc=$? ..||.. condition is false"
  $0  0   && echo "  \$0  0   rc=$? ..&&.. condition is true" || echo "  \$0  0   rc=$? ..||.. condition is false"
 ((1!=1)) && echo  " ((1!=1)) rc=$? ..&&.. condition is true" || echo  " ((1!=1)) rc=$? ..||.. condition is false"
  $0  1   && echo "  \$0  1   rc=$? ..&&.. condition is true" || echo "  \$0  1   rc=$? ..||.. condition is false"
echo
echo 'test 2: Now throw in some "unexpected" errors into the first of the &&/|| pair' 
echo  ======
 ((1==1)) && (echo  " ((1==1)) rc=$? ..&&.. condition is true"; $0 1)  || echo  " ((1==1)) rc=$? ..||.. condition is false"
  $0  0   && (echo "  \$0  0   rc=$? ..&&.. condition is true"; $0 2)  || echo "  \$0  0   rc=$? ..||.. condition is false"
 ((1!=1)) && (echo  " ((1!=1)) rc=$? ..&&.. condition is true"; $0 3)  || echo  " ((1!=1)) rc=$? ..||.. condition is false"
  $0  1   && (echo "  \$0  1   rc=$? ..&&.. condition is true"; $0 4)  || echo "  \$0  1   rc=$? ..||.. condition is false"
echo
echo 'test 3: Now swap the order of && and || statements, using "as expected" return codes'
echo  ======
 ((1==1)) || echo  " ((1==1)) rc=$? ..||.. condition is true" && echo  " ((1==1)) rc=$? ..&&.. condition is false"
  $0  0   || echo "  \$0  0   rc=$? ..||.. condition is true" && echo "  \$0  0   rc=$? ..&&.. condition is false"
 ((1!=1)) || echo  " ((1!=1)) rc=$? ..||.. condition is true" && echo  " ((1!=1)) rc=$? ..&&.. condition is false"
  $0  1   || echo "  \$0  1   rc=$? ..||.. condition is true" && echo "  \$0  1   rc=$? ..&&.. condition is false"
echo
echo 'test 4: With the order of && and || statements still swapped, introduce "unexpected" errors into the first of the &&/|| pair' 
echo  ======
 ((1==1)) && (echo  " ((1==1)) rc=$? ..&&.. condition is true"; $0 1)  || echo  " ((1==1)) rc=$? ..||.. condition is false"
  $0  0   && (echo "  \$0  0   rc=$? ..&&.. condition is true"; $0 2)  || echo "  \$0  0   rc=$? ..||.. condition is false"
 ((1!=1)) && (echo  " ((1!=1)) rc=$? ..&&.. condition is true"; $0 3)  || echo  " ((1!=1)) rc=$? ..||.. condition is false"
  $0  1   && (echo "  \$0  1   rc=$? ..&&.. condition is true"; $0 4)  || echo "  \$0  1   rc=$? ..||.. condition is false"

exit 

Peter.O
fonte
1

experimentar

false && echo "olá"

e

falso; eco "olá"

Veja a diferença

Petrie Wong
fonte
0

O comando (função, no caso de um script) depois &&é executado, dependendo do RETVAL do primeiro comando (função, no caso de um script). Força o primeiro comando a retornar um valor 0, se for bem-sucedido. Podemos verificar o valor de retorno para executar mais comandos.

theTuxRacer
fonte