Eu tenho um pequeno script, que é chamado diariamente por crontab usando o seguinte comando:
/homedir/MyScript &> some_log.log
O problema com esse método é que o some_log.log é criado somente após o término do MyScript. Eu gostaria de liberar a saída do programa no arquivo enquanto ele está em execução para que eu possa fazer coisas como
tail -f some_log.log
e acompanhar o progresso, etc.
O próprio bash nunca gravará nenhuma saída em seu arquivo de log. Em vez disso, os comandos que ele invoca como parte do script serão gravados individualmente e liberados sempre que quiserem. Então sua pergunta é realmente como forçar os comandos dentro do script bash para liberar, e isso depende do que eles são.
Eu encontrei uma solução para isso aqui . Usando o exemplo do OP você basicamente roda
stdbuf -oL /homedir/MyScript &> some_log.log
e, em seguida, o buffer fica liberado após cada linha de saída. Costumo combinar isso com nohup
para executar trabalhos longos em uma máquina remota.
stdbuf -oL nohup /homedir/MyScript &> some_log.log
Desta forma, o seu processo não será cancelado quando você sair.
script -c
A chave é -f. Citação do script man:
-f, --flush Flush output after each write. This is nice for telecooperation: one person does `mkfifo foo; script -f foo', and another can supervise real-time what is being done using `cat foo'.
Executado em segundo plano:
nohup script -c -f OUTPUT.txt
Você pode usar o tee
para gravar no arquivo sem a necessidade de liberar.
/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
Esta não é uma function do bash
, pois tudo que o shell faz é abrir o arquivo em questão e então passar o descritor de arquivo como a saída padrão do script. O que você precisa fazer é garantir que a saída seja liberada do seu script com mais frequência do que atualmente.
Em Perl, por exemplo, isso pode ser feito configurando:
$| = 1;
Veja perlvar para mais informações sobre isso.
Isso ajudaria?
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
Isso exibirá imediatamente inputs exclusivas do access.log
http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html
Como se viu aqui, o problema é que você tem que esperar que os programas que você executa a partir do seu script terminem seus trabalhos.
Se no seu script você executar o programa em segundo plano, poderá tentar algo mais.
Em geral, uma chamada para sync
antes de sair permite liberar buffers do sistema de arquivos e pode ajudar um pouco.
Se no script você iniciar alguns programas em segundo plano ( &
), poderá esperar que eles terminem antes de sair do script. Para ter uma ideia de como isso funciona, você pode ver abaixo
#!/bin/bash #... some stuffs ... program_1 & # here you start a program 1 in background PID_PROGRAM_1=${!} # here you remember its PID #... some other stuffs ... program_2 & # here you start a program 2 in background wait ${!} # You wait it finish not really useful here #... some other stuffs ... daemon_1 & # We will not wait it will finish program_3 & # here you start a program 1 in background PID_PROGRAM_3=${!} # here you remember its PID #... last other stuffs ... sync wait $PID_PROGRAM_1 wait $PID_PROGRAM_3 # program 2 is just ended # ...
Uma vez que wait
funciona com trabalhos, bem como com números PID
, uma solução preguiçosa deve ser colocar no final do script
for job in `jobs -p` do wait $job done
Mais difícil é a situação se você executar algo que execute algo em segundo plano, porque você tem que procurar e esperar (se for o caso) o fim de todo o processo filho : por exemplo, se você executar um daemon provavelmente não é o caso esperar que termine :-).
Nota:
wait $ {!} significa “espere até que o último processo em segundo plano seja concluído”, em que $!
é o PID do último processo em segundo plano. Então, para colocar em wait ${!}
Logo após o program_2 &
é equivalente a executar diretamente o program_2
sem enviá-lo em background com &
A partir da ajuda de wait
:
Syntax wait [n ...] Key n A process ID or a job specification
Buffer de saída depende de como o seu programa /homedir/MyScript
é implementado. Se você achar que a saída está sendo armazenada em buffer, será necessário forçá-la em sua implementação. Por exemplo, use sys.stdout.flush () se for um programa python ou use fflush (stdout) se for um programa em C.
Obrigado @user3258569
, script é talvez a única coisa que funciona no busybox
!
A casca estava congelando para mim depois disso, no entanto. Procurando pela causa, encontrei esses grandes avisos vermelhos “não use em shells não interativos” na página de manual do script :
script
é projetado principalmente para sessões de terminal interativas. Quando stdin não é um terminal (por exemplo:echo foo | script
), a session pode travar, porque o shell interativo dentro da session de script perde EOF e oscript
não tem idéia de quando fechar a session. Veja a seção NOTAS para mais informações.
Verdade. script -c "make_hay" -f /dev/null | grep "needle"
script -c "make_hay" -f /dev/null | grep "needle"
estava congelando a concha para mim.
Rural ao aviso, pensei que echo "make_hay" | script
echo "make_hay" | script
vai passar um EOF, então eu tentei
echo "make_hay; exit" | script -f /dev/null | grep 'needle'
e funcionou!
Observe os avisos na página man. Isso pode não funcionar para você.
Eu não sei se funcionaria, mas que tal chamar a sync
?
Eu tive esse problema com um processo em segundo plano no Mac OS X usando o StartupItems
. É assim que eu resolvo:
Se eu fizer o sudo ps aux
, posso ver que o mytool
é iniciado.
Descobri que (devido ao armazenamento em buffer) quando o Mac OS X é desligado, o mytool
nunca transfere a saída para o comando sed
. No entanto, se eu executar o sudo killall mytool
, o mytool
transferirá a saída para o comando sed
. Portanto, adicionei um caso de stop
aos StartupItems
que é executado quando o Mac OS X é desligado:
start) if [ -x /sw/sbin/mytool ]; then # run the daemon ConsoleMessage "Starting mytool" (mytool | sed .... >> myfile.txt) & fi ;; stop) ConsoleMessage "Killing mytool" killall mytool ;;
bem goste ou não, é assim que o redirecionamento funciona.
No seu caso, a saída (o que significa que o seu script terminou) do seu script redirecionado para esse arquivo.
O que você quer fazer é adicionar esses redirecionamentos ao seu script.