2009-09-15 11 views
47

Ho un piccolo script, che è chiamato ogni giorno da crontab utilizzando il seguente comando:Forza vampate di output in un file mentre bash script è ancora in esecuzione

/homedir/MyScript &> some_log.log 

Il problema di questo metodo è che some_log.log viene creato solo dopo aver terminato MyScript. Vorrei lavare l'output del programma nel file mentre è in esecuzione in modo da poter fare le cose come

tail -f some_log.log 

e tenere traccia dei progressi, ecc

+0

Avremo bisogno di avere una descrizione -o se possibile codice- di quello che il tuo piccolo script fa esattamente ... – ChristopheD

+4

Per gli script Python non buffer puoi usare "python -u". Per gli script perl di unbuffer, vedere la risposta di Greg Hewgill di seguito. E così via ... – Eloici

+0

Se è possibile modificare lo script, di solito è possibile svuotare il buffer di output in modo esplicito all'interno di uno script, ad esempio in python con 'sys.stdout.flush()'. – drevicko

risposta

21

bash non scriverà mai effettivamente alcun output nel file di registro. Invece, i comandi invocati come parte dello script scriveranno e arriveranno individualmente singolarmente ogni volta che ne avranno voglia. Quindi la tua domanda è davvero come forzare i comandi all'interno dello script di bash a svuotare, e questo dipende da cosa sono.

+1

Grazie, questo ha chiarito un po 'il problema. – olamundo

+2

Davvero non capisco questa risposta. –

+2

Per una migliore idea del perché l'output standard si comporta in questo modo, controlla http://stackoverflow.com/a/13933741/282728. Una versione breve: per impostazione predefinita, se reindirizzato a un file, stdout è completamente bufferizzato; è scritto su un file solo dopo un flush. Stderr non lo è, è scritto dopo ogni '\ n'. Una soluzione consiste nell'utilizzare il comando 'script' raccomandato dall'utente3258569 di seguito, per fare in modo che stdout venga svuotato dopo ogni fine riga. – Alex

2

Questa non è una funzione di bash , come tutta la shell fa è aprire il file in questione e quindi passare il descrittore di file come output standard dello script. Quello che devi fare è assicurarti che l'output sia svuotato dal tuo script più frequentemente di quello che sei attualmente.

In Perl, ad esempio, questo potrebbe essere realizzato impostando:

$| = 1; 

Vedi perlvar per ulteriori informazioni su questo.

-1

Non so se funzionerebbe, ma che dire di chiamare sync?

+0

'sync' è un'operazione di file system di basso livello e non è correlata all'output bufferizzato a livello di applicazione. –

+1

Dato che è possibile chiamare la sincronizzazione come comando, cosa fa allora? – forkandwait

+2

'sync' scrive eventuali buffer di filesystem sporchi nell'archiviazione fisica, se necessario. Questo è interno al sistema operativo; le applicazioni in esecuzione sul sistema operativo visualizzano sempre una vista coerente del filesystem indipendentemente dal fatto che i blocchi del disco siano stati scritti o meno sull'archiviazione fisica. Per la domanda originale, l'applicazione (script) probabilmente sta caricando l'output in un buffer interno all'applicazione, e il sistema operativo non saprà nemmeno (ancora) che l'output è effettivamente destinato a essere scritto su stdout. Quindi un'ipotetica operazione di tipo "sync" non sarebbe in grado di "raggiungere" lo script e tirare fuori i dati. –

-2

bene o non è così che funziona il reindirizzamento.

Nel tuo caso l'output (cioè lo script è finito) del tuo script reindirizzato a quel file.

Quello che vuoi fare è aggiungere quei reindirizzamenti nel tuo script.

-1

Ho riscontrato questo problema con un processo in background in Mac OS X utilizzando StartupItems. Ecco come lo risolvo:

Se faccio sudo ps aux Vedo che mytool viene lanciato.

Ho trovato che (a causa del buffering) quando Mac OS X si arresta, mytool non trasferisce mai l'output al comando sed. Tuttavia, se eseguo sudo killall mytool, quindi mytool trasferisce l'output al comando sed. Quindi, ho aggiunto un caso stop al StartupItems che viene eseguito quando Mac OS X si spegne:

start) 
    if [ -x /sw/sbin/mytool ]; then 
     # run the daemon 
     ConsoleMessage "Starting mytool" 
     (mytool | sed .... >> myfile.txt) & 
    fi 
    ;; 
stop) 
    ConsoleMessage "Killing mytool" 
    killall mytool 
    ;; 
8

È possibile utilizzare tee per scrivere sul file senza bisogno di risciacquo.

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null 
8

script -c <PROGRAM> -f OUTPUT.txt

chiave è -f. Citazione di scrittura dell'uomo:

-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'. 

eseguito in background:

nohup script -c <PROGRAM> -f OUTPUT.txt 
1

Come appena macchiato here il problema è che bisogna aspettare che i programmi che si esegue dallo script terminare il loro lavori.
Se nello script si esegue il programma in in background è possibile provare qualcosa di più.

In generale una chiamata a sync prima di uscire consente di svuotare i buffer del file system e può aiutare un po '.

Se nello script vengono avviati alcuni programmi in sfondo (&), si può wait che finire prima di uscire dallo script. Per avere un'idea di come può funzionare potete vedere qui sotto

#!/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 
# ... 

Dal wait opere con posti di lavoro nonché con PID numeri una soluzione pigra dovrebbe essere quello di mettere alla fine dello script

for job in `jobs -p` 
do 
    wait $job 
done 

Più difficile è la situazione se si esegue qualcosa che esegue qualcos'altro in background perché si deve cercare e attendere (se è il caso) la fine di tutto il processo figlio: ad esempio se si esegue un demone probabilmente non è il caso di aspettare finisce :-).

Nota:

  • attesa $ significa "aspettare l'ultimo processo in background viene completato" dove $! è il PID dell'ultimo processo in background {!}. Quindi, per mettere wait ${!} subito dopo program_2 & è equivalente a eseguire direttamente program_2 senza inviarlo in background con &

  • Da l'aiuto di wait:

    Syntax  
        wait [n ...] 
    Key 
        n A process ID or a job specification 
    
43

ho trovato una soluzione a questo here. Usando l'esempio del PO si esegue fondamentalmente

stdbuf -oL /homedir/MyScript &> some_log.log

e quindi il buffer si svuota dopo ogni riga di output. Spesso lo combino con nohup per eseguire lavori lunghi su una macchina remota.

stdbuf -oL nohup /homedir/MyScript &> some_log.log

In questo modo il processo non viene annullata quando si effettua il logout.

+1

Potresti aggiungere un collegamento ad alcuni documenti per 'stdbuf'? Basato su [questo commento] (http://stackoverflow.com/questions/1429951/bash-how-to-flush-output-to-a-file-while-running?answertab=votes#comment4951700_4520994) sembra che non sia disponibile su alcune distro. Potresti chiarire? –

+0

stdbuf -o regola il buffering stdout. Le altre opzioni sono -i e -e per stdin e stderr. L imposta il buffering di linea. Si potrebbe anche specificare la dimensione del buffer o 0 per nessun buffer. –

+2

questo link non è più disponibile. –

1

Il buffering dell'output dipende dal modo in cui è implementato il programma /homedir/MyScript. Se trovi che l'output viene bufferizzato, devi forzarlo nella tua implementazione. Ad esempio, usa sys.stdout.flush() se è un programma python o usa fflush (stdout) se è un programma C.

Problemi correlati