Em um script bash, eu gostaria de capturar a saída padrão de uma longa linha de comando por linha, para que eles possam ser analisados e relatados enquanto o comando inicial ainda está em execução. Esta é a maneira complicada que posso imaginar de fazer isso:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Eu gostaria de saber se existe uma maneira mais simples de fazer isso.
EDITAR:
Para esclarecer minha pergunta, adicionarei isso. Ele longcommand
exibe seu status linha por linha uma vez por segundo. Eu gostaria de pegar a saída antes da longcommand
conclusão.
Dessa forma, eu posso matar o potencial longcommand
se ele não fornecer os resultados esperados.
Eu tentei:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Mas whatever
(por exemplo echo
) só é executado após a longcommand
conclusão.
Respostas:
Basta canalizar o comando em um
while
loop. Existem várias nuances para isso, mas basicamente (embash
ou em qualquer shell POSIX):A outra pegadinha principal com isso (além das
IFS
coisas abaixo) é quando você tenta usar variáveis de dentro do loop quando ele terminar. Isso ocorre porque o loop é realmente executado em um sub-shell (apenas outro processo do shell) do qual você não pode acessar variáveis (também termina quando o loop o faz, e nesse ponto as variáveis desaparecem completamente. você pode fazer:Exemplo de configuração de Hauke
lastpipe
embash
outra solução.Atualizar
Para se certificar de que você está processando a saída do comando 'como acontece', você pode usar
stdbuf
para definir o processo 'stdout
para que seja buffer de linha.Isso configurará o processo para gravar uma linha de cada vez no canal, em vez de armazenar internamente sua saída em blocos. Cuidado que o programa pode alterar essa configuração internamente. Um efeito semelhante pode ser alcançado com
unbuffer
(parte deexpect
) ouscript
.stdbuf
está disponível nos sistemas GNU e FreeBSD, afeta apenas ostdio
buffer e funciona apenas para aplicativos não setuid e não setgid que são dinamicamente vinculados (como ele usa um truque LD_PRELOAD).fonte
IFS=
não é necessáriobash
, eu verifiquei isso após a última vez.line
(nesse caso, o resultado é inserido$REPLY
sem os espaços à esquerda e à direita aparados). Tente:echo ' x ' | bash -c 'read line; echo "[$line]"'
e compare comecho ' x ' | bash -c 'IFS= read line; echo "[$line]"'
ouecho ' x ' | bash -c 'read; echo "[$REPLY]"'
fonte