Qual é o equivalente a && ao escrever um script bash?


31

Peço desculpas antecipadamente se for uma pergunta duplicada. Fiz um esforço para pesquisar / verificar antes de perguntar aqui.

Estou confortável em escrever one-liners como este:

foocommand && foocommand2 && foocommand3

A ideia é que eu só quero que os comandos subseqüentes sejam executados se o anterior tiver "êxito".

Estou escrevendo um script um tanto demorado e essa linha única não é viável porque parece um enorme bloco de código confuso para todos os outros.

Quero espaçar os comandos e escrever comentários entre eles no script. Como posso fazer isso e ainda ter o equivalente de && lá?


4
Esta pena repetir: &&não significa que o comando posterior será executado se o anterior um foi bem sucedida. Isso significa que o comando será executado se o resultado coletivo de todos os comandos anteriores na lista de comandos for bem-sucedido. Você pode saber disso, mas os futuros leitores podem entender mal.
Kojiro #

1
Também como observação, esse comportamento que você está descrevendo é proveniente ||e &&(em oposição a |ou &) é chamado de curto-circuito. O comportamento usado com os últimos operadores é chamado de avaliação ansiosa.
21413 AndyPerfect

7
@kojiro: Não vejo a distinção. a && b && cserá executado apenas bse afor bem-sucedido; portanto, "ele só será executado cse bfor bem-sucedido" e "somente será executado cse ae bambos forem bem-sucedidos" são instruções equivalentes: bnão pode ser bem- asucedido a menos que seja bem- sucedido.
Ruakh

1
@ruakh a || b && cé mais ilustrativo.
Kojiro #

8
@ruakh não, true || false && echo hiserá exibido hi. A especificação diz: Os operadores "&&" e "||" deve ter precedência igual e ser avaliado com associatividade à esquerda.
Kojiro #

Respostas:


23

Você pode fazer assim:

#!/bin/sh
ls -lh &&
    # This is a comment
    echo 'Wicked, it works!'

Espero ter entendido o que você pediu corretamente.


Obrigado. Este é o mais próximo do que eu esperava fazer. E torna muito fácil a conversão novamente em um liner, se necessário.
Mike B

Mike, como você está preocupado com a limpeza do código, uma convenção comum é recuar as seções 2-N da cadeia abaixo da primeira.
jblaine

@ jblaine Não sei ao certo o que você quer dizer. Você pode por favor elaborar?
21813 Mike In B,

Mike, Stackexchange não vai me deixar formatar a minha resposta corretamente, isso aqui é tudo o que eu queria dizer: travessão
jblaine

@ jblaine Bom ponto, editado para recuar as linhas.
Volker Siegel

38

Você pode alterar a linha shebang para

#!/bin/bash -e

Após qualquer erro, o script será interrompido.


1
Interessante. Vou manter isso em mente. Obrigado.
Mike B

me salva do conjunto de digitação -e quando eu precisar dele
Silverrocker

@ Silverrocker Também é POSIX (exceto a bashparte do curso). O shell POSIX aceita várias opções aplicáveis set. Ou vice-versa? seté uma maneira de definir opções de linha de comando do shell no script.
Kaz

7
Infelizmente, existem vários utilitários padrão que não seguem as convenções usuais de status de saída e, portanto, -epodem se comportar mal. Por exemplo, você provavelmente não deseja que seu script seja finalizado toda vez que diffdois arquivos não idênticos. É claro que você pode contornar isso anexando || true(ou talvez || [ $? = 1 ]) esses comandos, mas o OP menciona um "todo mundo" que precisará ler esse script e disse que "todo mundo" provavelmente não estará acostumado a lidar com -e.
Ruakh 03/02

4
Eu costumava colocar -eno transexual, até que um administrador da minha empresa continuou lançando meus scripts bash myscript.sh, então ele ignorou o -e. Agora todos os meus scripts têm um set -ena segunda linha.
Carlos Campderrós

19

Se você não gosta da set -eideia, talvez possa inverter a lógica.

foocommand || exit 1
foocommand2 || exit 2
foocommand3 || exit 3

Mais útil, substitua exitpor algo para imprimir uma mensagem de erro útil e saia. Dentro de uma função, é claro, você deseja em returnvez de exit.


11
Ou foocommand || exitpara sair com foocommando status de saída, se diferente de zero.
Stéphane Chazelas 02/02

Como é que isso funciona? É como em C - se o argumento da esquerda for avaliado como TRUE, os argumentos não serão verificados?
Vorac 29/03

Sim está certo. É um idioma comum no Lisp (e linguagens funcionais em geral, suponho) e no Perl.
tripleee

9

Você pode usar if else fiblocos.

if foocommand; then

  # some comments

  if foocommand2; then

    # more comments

    foocommand3
  fi
fi

É um pouco mais legível.

Como alternativa, você pode usar apenas \para quebrar seu grande forro 1 em várias linhas

foocommand && \
  # some comment
  foocommand2 && \
    # more comment
    foocommand3

Mas é claro que isso pode ser confuso para os olhos não treinados.


4
Eu não acho que \é necessário lá.
Samuel Edwin Ward

Você está certo. Força do hábito.
Martín Canaval

5

Você pode considerar o uso de ifinstruções aninhadas . Outra opção é usar curly's para agrupar como{ true && echo hi; } || echo huh

Atualização 1:

Aqui está um exemplo sem novas linhas / comentários:

{ { false && echo "inner true"; } && { echo "inner true" && true; } || { echo "inner false" && false; } || echo "outter false"; }

@ Stephane Obrigado por adicionar ponto e vírgula. Estou usando meu telefone para responder, então não verifiquei minhas respostas duas vezes. :)
livingstaccato

Idéia interessante. Sim, pensei em declarações if aninhadas, mas se eu estiver encadeando muitas coisas, pode ficar confuso.
Mike B

4

Divida cada sequência de comandos em funções:

big_block_1() {
  # ...
}
big_block_2() {
  # ...
}
big_block_3() {
  # ...
}

big_block_1 && big_block_2 && big_block_3

0

Eu sempre gosto de escrever uma função "falha" que me permite especificar o que eu faria quando a falha ocorreu e depois usar o ||padrão. Como o seguinte:

function fail() {
  echo "Failure: ${@}"
  exit 1
}

foocommand || fail "couldn't foo"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.