Bash script och redirect

När man skriver Bash-script eller håller på med olika kommandon så händer det titt som tätt att man behöver skicka texten som kommer ut från ett kommando till en fil, till ett annat kommando eller helt enkelt filtrera bort text. Det kan man lösa med redirect.

Om vi t.ex. vill skriva dagens datum till en textfil kan man ju skriva så här:
root@vps-nnnnn:~# date +"%Y-%m-%d" > textfil.txt
root@vps-nnnnn:~# cat textfil.txt
2011-07-17

Vi omdirigerar standard output till filen textfil.txt. Inga konstigheter.

Om kommandot vi vill omdirigera, i det här fallet date, skriver ut ett felmeddelande så blir det däremot lite annorlunda. Vi råkar t.ex. glömma +-tecknet:
root@vps-nnnnn:~# date "%Y-%m-%d" > textfil.txt
date: invalid date `%Y-%m-%d'
root@vps-nnnnn:~# cat textfil.txt

Textfilen textfil.txt är nu tom och felmeddelandet kom inte till filen utan direkt till skärmen. I vissa fall kanske vi vill ha med felmeddelandet till textfilen om t.ex. ett annat script ska läsa innehållet.

Ett nytt exempel, vi vill räkna antal GET som förekommer i Apache-loggen:
root@vps-nnnnn:~# cat /var/log/apache2/access.log | grep -c GET
289

Det fungerar ju bra, men om inte access.log råkar finnas så kommer det med ett felmeddelande:
root@vps-nnnnn:~# cat /var/log/apache2/access.log | grep -c GET
cat: /var/log/apache2/access.log: No such file or directory
0

Det blir ju inte så snyggt. Istället kan vi skriva:
root@vps-nnnnn:~# cat /var/log/apache2/access.log 2>/dev/null | grep -c GET
0

Vad gjorde vi här? Vi styrde om alla felmeddelanden (standard error) till /dev/null. Vanlig text (standard output) visas som tidigare.

Manualen för Bash visar syntaxen:

COMMAND > FILENAME REDIRECT STANDARD OUTPUT TO FILENAME
COMMAND M>N FILE DESCRIPTOR M IS REDIRECTED TO FILE N
COMMAND M>&N FILE DESCRIPTOR M IS REDIRECTED TO DESCRIPTOR N
COMMAND 1>FILENAME REDIRECT DESCRIPTOR 1 (STDOUT) TO FILENAME
COMMAND 2>FILENAME REDIRECT DESCRIPTOR 2 (STDERR) TO FILENAME
COMMAND &>FILENAME REDIRECT STDOUT AND STDERR TO FILENAME
COMMAND 2>&1 REDIRECTS STDERR TO STDOUT
COMMAND 2>&1 | [COMMAND(S)] SENDS STDERR THROUGH A PIPE

Ytterligare några exempel kommer här. För att undvika all text från ett kommando så styr vi om både standard output och standard error till /dev/null:
pushd /etc &> /dev/null

Eller för att skicka alla felmeddelanden till en fel-log och resten till skärmen:
find / -name "hosts" 2> /var/log/error_log