Substituição de comando $(...)
transforma a saída em argumentos. Primeiro precisa de toda a saída, porque não é possível fornecer argumentos dinamicamente um por um.
Estou tentando fazer algo que envolve scripts chamando outros scripts em subshells para capturar sua saída.
Um dos scripts precisa ter um efeito colateral de iniciar um processo em segundo plano. Isso tudo funciona quando executado diretamente, mas bloqueia quando chamado dentro de um subshell.
Como um exemplo independente, considere os seguintes 2 scripts:
test1.sh
#!/bin/bash
echo $(./test2.sh)
test2.sh
#!/bin/bash
(yes > /dev/null ; echo 'yes killed') &
echo success
Quando executo test2.sh
por si só, obtenho o resultado esperado de "sucesso" no terminal e yes
em execução em segundo plano. Matando yes
imprime "sim, foi eliminado" no terminal como esperado.
Quando eu executo test1.sh
, espero obter o mesmo comportamento, mas o que realmente acontece é que o terminal trava até eu matar yes
, após o qual "sucesso sim é morto" é impresso no terminal. / p>
O que altero para esses scripts para que eu possa fazer com que o mesmo comportamento seja chamado de um deles?
A premissa aqui é que a avaliação do subshell em test1.sh
será realmente armazenada em uma variável para uso posterior. O processo em segundo plano iniciado em test2.sh
deve passar da execução de qualquer script.
Substituição de comando $(...)
transforma a saída em argumentos. Primeiro precisa de toda a saída, porque não é possível fornecer argumentos dinamicamente um por um.
Como sugerido @choroba e @GordonDavisson, a substituição de comando $( ... )
não retornará até que toda a sua stdout tenha sido desconectada [1] .
O truque aqui é que, mesmo se você redirecionar todos os stdout dos comandos, a subshell por si mesma, por exemplo. ( ... )
ainda tem seu stdout anexado. Isso significa que o seguinte não funcionará:
#!/bin/bash
(yes > /dev/null ; echo 'yes killed' > /dev/null) &
echo success
Mas isso vai:
#!/bin/bash
(yes ; echo 'yes killed' ) > /dev/null &
echo success
Observação: você não receberá mais nenhuma saída para o terminal ou stdout dessa forma, mas, para mim, isso não é um problema. Se necessário, você pode sempre redirecionar para um arquivo ou algo assim, se a saída for necessária
[1] Veja também link
Eu acho que o do bash é a resposta. Veja help disown
.
Use assim:
yes &>/dev/null </dev/zero &
disown -h $!
Redirecionar a saída ou o terminal de fechamento resultaria em sinal SIGHUP ou um cano quebrado para saída (SIGPIPE) eventualmente bloqueando ou matando o programa.
Se você se preocupa com a saída, redirecione-a para um arquivo. Ou use nohup assim:
nohup yes &
disown $!
Uma boa explicação do nohup e do disown.
Você não precisa do eco para executar outro script de shell
#!/bin/bash
#echo $(./test2.sh)
./test2.sh