Precedência de operadores lógicos versus ponto e vírgula

7

O que acontecerá se eu escrever uma linha no bash como

commandA && commandB ; commandC

Se commandA falhar, commandC será executado?

    
por user20273 13.06.2017 / 15:13

4 respostas

10

Sim, e você pode conferir você mesmo com facilidade:

$ non-existent-command && echo hi ; echo after semicolon
bash: non-existent-command: command not found
after semicolon

Em man bash , diz:

Commands separated by a ; are executed sequentially; the shell waits for each command to terminate in turn.

    
por 13.06.2017 / 15:16
3

commandC será executado independentemente de commandA ou commandB falhar ou ser bem-sucedido.

O ponto-e-vírgula é apenas um separador para fazer com que os comandos sejam executados sequencialmente. O único cenário em que posso ver onde commandC falhará será se commandA ou commandB forem Comandos exit (ou qualquer comando como return / break / continue / exec (ou funções que os chamam) que afetam forçosamente o fluxo de trabalho):

Cenário 1: commandA é exit

[root@host ~]# exit && echo "HI"; echo "test"
logout
[user@host ~]$

Cenário 2: commandB é exit

[root@host~]# echo "HI" && exit; echo "test"
HI
logout
[user@host ~]$

tl; dr: Não é que esses caracteres tenham precedência. Eles significam coisas diferentes. Um é um operador lógico e o outro é um terminador de lista.

Itens relacionados:

  • Quais são os operadores de controle e redirecionamento do shell? Esta resposta dá uma boa explicação sobre os operadores do bash. Citando um pequeno pedaço da resposta:

    • ; : Will run one command after another has finished, irrespective of the outcome of the first.

      command1 ; command2
      

      First command1 is run, in the foreground, and once it has finished, command2 will be run.

      A newline that isn't in a string literal or after certain keywords is not equivalent to the semicolon operator. A list of ; delimited simple commands is still a list - as in the shell's parser must still continue to read in the simple commands that follow a ; delimited simple command before executing, whereas a newline can delimit an entire command list - or list of lists. The difference is subtle, but complicated: given the shell has no previous imperative for reading in data following a newline, the newline marks a point where the shell can begin to evaluate the simple commands it has already read in, whereas a ; semi-colon does not.

  • ponto e vírgula supérfluo no final de um linha em scripts de shell? Citando a resposta:

    Single semicolons at the end of a line are superfluous, since the newline is also a command separator. case specifically needs double semicolons at the end of the last command in each pattern block; see help case for details.

  • Qual é a diferença entre ponto-e-vírgula e duplo-comercial? & &

por 13.06.2017 / 15:48
1

de acordo com a página man bash

[L]ist operators, && and || have equal precedence, followed by ; and &, which have equal precedence.

Na prática, isso se resume a quem se importa com o resultado de retorno. Se o resultado for necessário imediatamente, tem maior precedência.

    
por 14.06.2017 / 00:17
1

Como outros posts disseram, a resposta curta é “Sim, commandC será executado independentemente do que acontecer.”

Como nwildner explorou , a resposta mais longa é: "Sim, commandC será executado independentemente do que mais acontecer, contanto que a casca ainda esteja em uma condição em que ele pode executar commandC . Em outras palavras, o shell não irá além do

commandA && commandB ; command

linha de comando sem executar commandC . ”

De forma trivial, se commandA (ou commandB ) for kill -KILL $$ ou qualquer outra coisa que termine ou ameace a concha, ou interrompe o fluxo de comando, então commandC não será executado. (Claramente estamos falando de casos de borda aqui.) O comportamento é um pouco diferente se set -e (ou, equivalentemente, set -o errexit ) foi emitido:

  • Se commandA falhar, commandC será executado (mas commandB não será).
  • Se commandA for bem-sucedido, então commandB será executado.
    • Se commandB for bem-sucedido, então commandC será executado.
    • Se commandB falhar, o shell sairá, e commandC não será executado.

A opção errexit especifica que o shell deve sair se algum comando (qualquer “pipeline”) falhar, com algumas exceções:

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !.

— from bash(1)

Então, se commandA falhar, isso só fará com que commandB não seja executado, porque commandA é seguido por && . Mas se commandB for executado e falhar, isso fará com que o shell saia porque ( commandB ) segue o (final) && .

    
por 14.06.2017 / 04:34

Tags