Når du bruger nohup til at sætte en kommando til at køre i baggrunden, vises noget af indholdet i terminalen.
cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error
Jeg ønsker at gemme dette indhold til en fil.
Der er to hoveduddatastrømme i Linux (og andre operativsystemer), standard output (stdout) og standard error (stderr). Fejlmeddelelser, som dem du viser, udskrives til standardfejl. Den klassiske omdirigeringsoperator (command > file
) omdirigerer kun standard output, så standard error vises stadig på terminalen. For også at omdirigere stderr har du et par valgmuligheder:
Omdiriger stdout til en fil og stderr til en anden fil:
command > out 2>error
Omdiriger stdout til en fil (>out
), og omdiriger derefter stderr til stdout (2>&1
):
command >out 2>&1
Omdiriger begge dele til en fil (dette er ikke understøttet af alle shells, bash
og zsh
understøtter det for eksempel, men sh
og ksh
gør ikke):
command &> out
For flere oplysninger om de forskellige kontrol- og omdirigeringsoperatorer, se her.
Den første ting at bemærke er, at der er et par måder afhængigt af dit formål og din skal, og derfor kræver dette en lille forståelse af flere aspekter. Derudover skriver visse kommandoer som time
og strace
output til stderr som standard, og kan eller kan ikke give en metode til omdirigering, der er specifik for den pågældende kommando
Den grundlæggende teori bag omdirigering er, at en proces, der spawner af shell (forudsat at det er en ekstern kommando og ikke en indbygget shell), oprettes via fork()
og execve()
syscalls, og før det sker, udfører et andet syscall dup2()
de nødvendige omdirigeringer, før execve()
sker. I den forstand arves omdirigeringer fra den overordnede shell. m&>n
og m>n.txt
informerer shell'en om hvordan open()
og dup2()
syscall skal udføres (se også How input redirection works, What is the difference between redirection and pipe, og What does & exactly mean in output redirection )
Det mest typiske er via 2>
i Bourne-lignende skaller, såsom dash
(som er symlinket til /bin/sh
) og bash
; den første er standard og POSIX-kompatibel shell, og den anden er hvad de fleste brugere bruger til interaktive sessioner. De adskiller sig i syntaks og funktioner, men heldigvis for os fungerer fejlstrømsomdirigeringen på samme måde (bortset fra den &>
ikke-standardiserede). I tilfælde af csh og dets derivater, stderr omdirigering virker ikke helt der.
Lad os komme tilbage til 2>
-delen. To vigtige ting at bemærke: >
betyder omdirigeringoperator, hvor vi åbner en fil og 2
heltal står for stderr fildeskriptor; faktisk er det præcis sådan POSIX-standarden for shellsprog definerer omdirigering i afsnit 2.7:
[n]redir-op word
For simpel >
omdirigering, er det hele tal 1
implicit for stdout
, dvs. echo Hello World > /dev/null
er bare det samme som echo Hello World 1>/dev/null
. Bemærk, at integer eller redirection operatoren ikke kan være i citationstegn, da shell ellers ikke genkender dem som sådan, og i stedet behandler dem som en bogstavelig tekststreng. Med hensyn til mellemrum er det vigtigt at integer er lige ved siden af redirection-operatoren, men file kan enten være ved siden af redirection-operatoren eller ej, dvs. command 2>/dev/null
og command 2> /dev/null
vil fungere fint.
Den noget forenklede syntaks for en typisk kommando i en shell ville være
command [arg1] [arg2] 2> /dev/null
Tricket her er, at omdirigering kan forekomme hvor som helst. Det vil sige, at både 2> command [arg1]
og command 2> [arg1]
er gyldige. Bemærk at for bash
shell, findes der &>
måde at omdirigere både stdout og stderr streams på samme tid, men igen - det er bash-specifikt, og hvis du stræber efter portabilitet af scripts, virker det måske ikke. Se også Ubuntu Wiki og Hvad er forskellen mellem &> og 2>&1.
Note: Operatoren >
omdirigeringsoperatoren afkorter en fil og overskriver den, hvis filen findes. 2>>>
kan bruges til at tilføje stderr
til filen.
Hvis du måske bemærker det, er >
beregnet til en enkelt kommando. For scripts kan vi omdirigere stderr-strømmen for hele scriptet udefra som i myscript.sh 2> /dev/null
eller vi kan gøre brug af exec built-in. Den indbyggede exec har mulighed for at omdirigere strømmen for hele shell-sessionen, så at sige, uanset om det er interaktivt eller via script. Noget i stil med
#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file
I dette eksempel skulle logfilen vise stat: cannot stat '/etc/non_existing_file': No such file or directory
.
Endnu en anden måde er via funktioner. Som kopciuszek bemærkede i sit svar, kan vi skrive en funktionsdeklaration med en allerede vedhæftet omdirigering, dvs.
some_function(){
command1
command2
} 2> my_log_file.txt
Kommandoer som time
og strace
skriver som standard deres output til stderr. I tilfælde af kommandoen time
er det eneste brugbare alternativ at omdirigere output af hele kommandoen, dvs.
time echo foo 2>&1 > file.txt
alternativt kan synkron liste eller subshell omdirigeres, hvis du ønsker at adskille output ( som vist i relateret indlæg ):
{ time sleep 1 2> sleep.stderr ; } 2> time.txt
Andre kommandoer, såsom strace
eller dialog
giver mulighed for at omdirigere stderr. strace
har -o <filnavn.txt>
mulighed, som gør det muligt at angive filnavn, hvor output skal skrives. Der er også en mulighed for at skrive en tekstfil for hver underproces, som strace
ser. Kommandoen dialog
skriver tekstbrugergrænsefladen til stdout, men output til stderr, så for at gemme dens output til en variabel ( fordi var=$(...)
og pipelines kun modtager stderr ) skal vi bytte om på fildeskriptorerne
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
men derudover er der --output-fd
-flag, som vi også kan udnytte. Der'er også metoden med navngivne pipes. Jeg anbefaler at læse det linkede indlæg om kommandoen dialog
for en grundig beskrivelse af hvad'der sker.