Mentre si usa nohup per mettere un comando da eseguire in background alcuni contenuti appaiono nel terminale.
cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error
Voglio salvare quel contenuto in un file.
Ci sono due flussi di output principali in Linux (e in altri sistemi operativi), l'output standard (stdout) e l'errore standard (stderr). I messaggi di errore, come quelli mostrati, vengono stampati su standard error. Il classico operatore di reindirizzamento (comando > file
) reindirizza solo l'output standard, quindi l'errore standard viene ancora mostrato sul terminale. Per reindirizzare anche stderr, avete alcune scelte:
Reindirizzare stdout a un file e stderr a un altro file:
command > out 2>error
Reindirizza lo stdout ad un file (>out
), e poi reindirizza lo stderr allo stdout (2>&1
):
comando >out 2>&1
Reindirizzare entrambi a un file (questo non è supportato da tutte le shell, bash
e zsh
lo supportano, per esempio, ma sh
e ksh
no):
comando &> out
Per maggiori informazioni sui vari operatori di controllo e reindirizzamento, vedere qui.
La prima cosa da notare è che ci sono un paio di modi a seconda del vostro scopo e della vostra shell, quindi questo richiede una leggera comprensione di più aspetti. Inoltre, alcuni comandi come time
e strace
scrivono l'output su stderr per default, e possono o non possono fornire un metodo di reindirizzamento specifico per quel comando.
La teoria di base dietro il reindirizzamento è che un processo generato dalla shell (assumendo che sia un comando esterno e non integrato nella shell) viene creato tramite le syscall fork()
e execve()
, e prima che ciò accada un'altra syscall dup2()
esegue i reindirizzamenti necessari prima che avvenga execve()
. In questo senso, i reindirizzamenti sono ereditati dalla shell madre. Le istruzioni m&>n
e m>n.txt
informano la shell su come eseguire le syscall open()
e dup2()
(vedi anche Come funziona il reindirizzamento dell'input, Qual è la differenza tra reindirizzamento e pipe, e Cosa significa esattamente & nel reindirizzamento dell'output )
Il più tipico, è tramite 2>
nelle shell Bourne-like, come dash
(che è symlinked a /bin/sh
) e bash
; la prima è la shell di default e conforme a POSIX e l'altra è quella che la maggior parte degli utenti usa per la sessione interattiva. Differiscono nella sintassi e nelle caratteristiche, ma fortunatamente per noi il reindirizzamento dei flussi di errore funziona allo stesso modo (tranne quello &>
non standard). Nel caso di csh e dei suoi derivati, il reindirizzamento stderr non vi funziona del tutto.
Torniamo alla parte 2>
. Due cose chiave da notare: >
significa operatore di reindirizzamento, dove apriamo un file e 2
intero sta per descrittore di file stderr; infatti questo è esattamente come lo standard POSIX per il linguaggio shell definisce il reindirizzamento nella sezione 2.7:
[n]redir-op word
Per il semplice >
reindirizzamento, l'intero 1
è implicito per stdout
, cioè echo Hello World > /dev/null
è proprio lo stesso di echo Hello World 1>/dev/null
. Si noti che l'intero o l'operatore di reindirizzamento non possono essere quotati, altrimenti la shell non li riconosce come tali, e li tratta invece come stringhe letterali di testo. Per quanto riguarda la spaziatura, è importante che l'intero sia proprio accanto all'operatore di reindirizzamento, ma il file può essere accanto all'operatore di reindirizzamento oppure no, cioè comando 2>/dev/null
e comando 2>/dev/null
funzioneranno bene.
La sintassi un po' semplificata per un tipico comando in shell sarebbe
command [arg1] [arg2] 2> /dev/null
Il trucco qui è che il reindirizzamento può apparire ovunque. Cioè sia 2> comando [arg1]
che comando 2> [arg1]
sono validi. Si noti che per la shell bash
, esiste un modo &>
per reindirizzare entrambi i flussi stdout e stderr allo stesso tempo, ma di nuovo - è specifico di bash e se si sta cercando la portabilità degli script, potrebbe non funzionare. Vedi anche Ubuntu Wiki e Qual è la differenza tra &> e 2>&1.
Nota: L'operatore di reindirizzamento >
truncates un file e lo sovrascrive, se il file esiste. Il 2>>
può essere usato per aggiungere stderr
al file.
Se puoi notare, >
è inteso per un singolo comando. Per gli script, possiamo reindirizzare il flusso stderr dell'intero script dall'esterno come in myscript.sh 2> /dev/null
o possiamo fare uso di exec built-in. L'exec built-in ha il potere di ricablare il flusso per l'intera sessione di shell, per così dire, sia interattivamente che tramite script. Qualcosa come
#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file
In questo esempio, il file di log dovrebbe mostrare stat: cannot stat '/etc/non_existing_file': No such file or directory
.
Un altro modo è tramite le funzioni. Come kopciuszek ha notato nella sua risposta, possiamo scrivere una dichiarazione di funzione con reindirizzamento già allegato, cioè
some_function(){
command1
command2
} 2> my_log_file.txt
Comandi come time
e strace
scrivono il loro output su stderr per default. Nel caso del comando time
, l'unica alternativa possibile è reindirizzare l'output dell'intero comando, cioè
time echo foo 2>&1 > file.txt
In alternativa, la lista sincrona o la subshell potrebbero essere reindirizzate se si vuole separare l'output (come mostrato in related post):
{ time sleep 1 2> sleep.stderr ; } 2> time.txt
Altri comandi, come strace
o dialog
forniscono mezzi per reindirizzare stderr. strace
ha l'opzione -o <filename.txt>
che permette di specificare il nome del file dove l'output dovrebbe essere scritto. C'è anche un'opzione per scrivere un file di testo per ogni sottoprocesso che strace
vede. Il comando dialog
scrive l'interfaccia utente testuale su stdout ma l'output su stderr, quindi per salvare il suo output su una variabile ( perché var=$(...)
e pipeline riceve solo stderr ) dobbiamo scambiare i descrittori di file
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
ma in aggiunta, c'è il flag --output-fd
, che possiamo anche utilizzare. C'è anche il metodo delle named pipes. Raccomando di leggere il post collegato sul comando dialog
per una descrizione approfondita di ciò che succede.