Bash: maneira elegante de definir o status? [fechadas]

3
  • true && echo foo imprimirá foo .
  • false && echo foo não imprime foo .
  • bash -c "exit $a" && echo foo imprimirá foo dependendo de $a .

Existe uma maneira mais elegante de escrever o último? Parece um pouco demais ter que iniciar um shell simplesmente para definir o valor de saída. Estou pensando em algo como:

  • return $a && echo foo
  • exit $a && echo foo

exceto return só funciona em funções e exit fará com que echo foo nunca seja executado.

Elegante neste contexto significa:

  • Fácil de entender
  • Portátil
  • Fácil de ler
  • Fácil de escrever
  • Fácil de lembrar
  • Curto
  • Alto desempenho

Por exemplo Se true tomou o código de saída como um argumento (e este era um recurso documentado), seria muito elegante.

Então, há uma maneira mais elegante?

Plano de fundo

Um dos locais em que isso pode ser usado é:

$ parallel 'setexitval {= $_%=3 =} || echo $?' ::: 0 1 2 3  

A versão de Kusalananda é provavelmente a melhor. Está claro o que está acontecendo. Não é longo e complicado escrever. É fácil de lembrar e portátil. O único inconveniente é que ele bifurca outra casca:

$ parallel '(exit {= $_%=3 =}) || echo $?' ::: 0 1 2 3  

Outra situação é quando você deseja simular uma condição de erro. Digamos que, se você tiver um programa de longa duração, isso define códigos de saída diferentes e você está escrevendo algo que reagirá aos diferentes códigos de saída. Em vez de ter que executar o programa de longa duração, você pode usar (exit $a) para simular a condição.

    
por Ole Tange 12.02.2018 / 21:55

4 respostas

6

Use um subshell que saia com o valor especificado.

Isso gerará 5 :

a=5; ( exit $a ) && echo foo; echo $?

Isso produzirá foo e 0 (note que este zero é definido por echo sucessor, não pelo exit no subshell):

a=0; ( exit $a ) && echo foo; echo $?

Na sua forma abreviada (sem definir visivelmente a ou investigar $? explicitamente):

( exit $a ) && echo foo

Minha resposta é aquela que vem de apenas responder à pergunta e resolvê-la como um teste curioso, "como podemos definir $? (usando notação útil)". Eu não faço nenhuma tentativa de procurar qualquer significado ou função mais profunda ou mesmo contexto neste caso (porque o non foi dado). Eu também não julgo a validade, eficiência ou usabilidade da solução. Às vezes, em minhas respostas, digo coisas como "... mas não faça isso, porque ...", seguido de "em vez disso, faça isso ...". Neste caso, escolho interpretar a questão simplesmente como um teste curioso.

Mais informações foram adicionadas à pergunta.

Minha abordagem da bifurcação de um subshell é que scripts como o GNU configure fazem isso o tempo todo , e que não é terrivelmente lento, a menos que seja feito de uma forma muito apertada (longa duração) loop.

Eu não posso falar muito sobre o uso disso em / com o GNU parallel , já que não sou usuário frequente desse software.

    
por 12.02.2018 / 22:19
12

Bem, return funciona em uma função, então vamos criar uma:

$ ret() { return "${1-0}"; }
$ ret 1 || echo foo
foo
$ ret 123 ; echo $?
123

Ele precisa de um pouco mais de configuração do que um subshell, mas é mais curto para ser usado depois disso, e não requer o forking de um subshell.

    
por 12.02.2018 / 22:33
4

Uma opção (provavelmente mais rápida, mas não muito mais elegante):

test "$a" -eq 0 && echo foo

Ele executa echo , mas não define o valor de saída como $a , por isso é uma solução medíocre.

    
por 12.02.2018 / 21:58
4

Vamos examinar suas suposições:

  • true && echo foo será impresso foo. Correto porque && adere ao AND com lógica de curto-circuito; devido à associatividade à esquerda nos operadores && e || se o comando mais à esquerda retornou o status de saída com êxito 0 (que true faz sempre), o comando mais à direita para esse operador será executado.

  • false && echo foo não será impresso foo. Exatamente o caso oposto de explicado acima.

  • bash -c "exit $a" && echo foo será impresso de acordo com $a . Suposição essencialmente errada de que $a controla && . Como && é AND, ele reconhece apenas dois estados - sucesso ou falha, em que a falha é qualquer status de saída acima de 0. Assim, exit 1 e exit 2 e exit 3 - todos são irrelevantes para && ; falha é falha independentemente do valor $a ; é por isso que echo foo não funciona.

Portanto, a resposta é não, não há uma maneira mais elegante de fazer algo que funcione sob a hipótese errada. No entanto, se o seu propósito é definir o status de saída por meio do comando, isso é suficiente para usar o que a resposta de Kusalananda sugere - uma subcamada. Eu pessoalmente não vejo nada diferente de bash -c part, exceto que subshell pode ser implementado como processo filho / processo bifurcado ao invés de processo separado; ainda não é ideal. Note que $? também não deve ser definido pelo usuário via variável - é destinado a comandos para comunicar sucesso ou falha.

Vamos mudar o foco em $a por um segundo. Por que definir $? e echo foo , se você puder verificar diretamente $a ? Não faz sentido colocar o valor $a onde ele não pertence de qualquer maneira, ou seja, em $? . Eu recomendaria mudar o foco de "elegante" (o que quer que isso signifique) para "lógico" e "trabalho".

Tudo bem, mas vamos jogar o seu jogo. Inspirando-se modestamente na resposta do ilkkachu . Essa abordagem, no entanto, elimina a necessidade de forçar a execução condicional de eco. Ele irá ecoar se uma variável somente se fornecida indicar sucesso, e return impede sua execução.

$ thing(){ [ "${1-0}" -eq 0 ] || return "$1" ; echo "foo"; }
$ thing
foo
$ thing 0
foo
$ thing 1
$ echo $?
1
$ thing 2
$ echo $?
2

O que pode não ser óbvio é que você pode fazer thing $a

    
por 12.02.2018 / 23:22