Quero que meus scripts de shell falhem sempre que um comando executado com eles falhar.
Normalmente faço isso com:
set -e
set -o pipefail
(normalmente eu adiciono set -u
também)
O fato é que nenhuma das opções acima funciona com substituição de processo. Este código imprime "ok" e sai com o código de retorno = 0, enquanto eu gostaria que falhasse:
#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)
Existe algo equivalente a "pipefail", exceto para substituição de processo? Qualquer outra maneira de passar para um comando a saída dos comandos como se fossem arquivos, mas gerando um erro sempre que algum desses programas falha?
A solução do homem pobre seria detectar se esses comandos gravam no stderr (mas alguns comandos gravam no stderr em cenários de sucesso).
Outra solução mais compatível com posix seria usar pipes nomeados, mas eu preciso usar esses comandos que usam substituição de processo como oneliners criados em tempo real a partir de código compilado, e a criação de pipes nomeados complicaria as coisas (comandos extras, erro de interceptação para excluí-los etc.)
fonte
mkfifo pipe; { rm pipe; cat <file; } >pipe
. Esse comando será interrompido até que um leitor seja abertopipe
porque é o shell que executa o procedimentoopen()
e assim que houver um leitor nopipe
link fspipe
forrm
'd e, em seguida,cat
copie o infile para o descritor do shell para esse canal. E de qualquer maneira, se você deseja propagar um erro de um processo sub do: <( ! : || kill -2 "$$")
$$
substituição não funciona para mim, pois essa substituição de comando não é feita, pois o comando que usa substituição de processo é feito dentro de um pipeline de comando gerado a partir de um código "não shell" (python). Provavelmente eu deveria criar subprocessos em python e canalizá-los programaticamente.kill -2 0
.Respostas:
Você só poderia solucionar esse problema com isso, por exemplo:
O subshell do script é
SIGTERM
d antes que o segundo comando possa ser executado (other_command
). Oecho ok
comando é executado "algumas vezes": O problema é que as substituições de processos são assíncronas. Não há garantia de que okill $$
comando seja executado antes ou depois doecho ok
comando. É uma questão de agendamento de sistemas operacionais.Considere um script bash como este:
A saída desse script pode ser:
Ou:
Você pode tentar e depois de algumas tentativas, verá as duas ordens diferentes na saída. No primeiro, o script foi finalizado antes que os outros dois
echo
comandos pudessem gravar no descritor de arquivo. No segundo,false
okill
comando ou provavelmente foi agendado após osecho
comandos.Ou, para ser mais preciso: a chamada
signal()
do sistema dakill
utilidade que envia oSIGTERM
sinal para o processo de shells foi agendada (ou foi entregue) mais tarde ou mais cedo que oswrite()
syscalls do eco .Mas, no entanto, o script é interrompido e o código de saída não é 0. Portanto, ele deve resolver seu problema.
Outra solução é, é claro, usar pipes nomeados para isso. Mas, depende do seu script o quão complexo seria implementar pipes nomeados ou a solução alternativa acima.
Referências:
fonte
Para o registro, e mesmo que as respostas e os comentários fossem bons e úteis, eu acabei implementando algo um pouco diferente (eu tinha algumas restrições sobre o recebimento de sinais no processo pai que não mencionei na pergunta)
Basicamente, acabei fazendo algo assim:
Então eu verifico o arquivo de erro. Se existir, sei qual subcomando falhou (e o conteúdo do arquivo error_file pode ser útil). Mais detalhado e hackeado do que eu originalmente queria, mas menos complicado do que criar pipes nomeados em um comando bash de uma linha.
fonte
Este exemplo mostra como usar
kill
junto comtrap
.Mas
kill
não é possível transmitir um código de retorno do seu subprocesso para o processo pai.fonte
De maneira semelhante à que você implementaria
$PIPESTATUS
/$pipestatus
com um shell POSIX que não o suporta , é possível obter o status de saída dos comandos passando-os por um canal:Que dá:
Ou você pode usar
pipefail
e implementar a substituição do processo manualmente, como faria com shells que não o suportam:fonte