explanation of redirections [ was Re: WARNING - BLFS CVS CHANGES!]

Matthias Benkmann matthias at winterdrache.de
Thu Oct 25 04:01:13 PDT 2001


On 25 Oct 2001, at 11:52, Sebastian Edman wrote:

> At 17:41 2001-10-24, Mark wrote:
> >                        /home/mark/LFS/LFS/BOOK/index.xml 2>&1 > html.log
> >         fi
> >
> >Though I probably should say that the html.log file doesn't recieve any
> >output - the redirection doesn't seem to work ;-)
> 
> It isnt supposed to work that way, why I cant explain (I read it in 
> Advanced Bash Scripting Guide I think but cant find it again). Change the
> order and use /home/mark/LFS/LFS/BOOK/index.xml > html.log 2>&1 instead, it
> works.

It's not that hard to understand. The following points you have to keep in 
mind:

a) Every stream has a file descriptor associated with it. A file 
descriptor is simply a number. 0 is stdin, 1 is stdout, 2 is stderr. You 
can use more if you need to.

b) You should read the construct  "x >& y"  as "x becomes (a copy of) y". 
It's like an assignment to a shell variable "x= $y".
The same is true for ">", "<", ...  No matter where the arrow points and 
no matter if it has or does not have a "&" in it, it must always be read
"x becomes y", i.e. left side becomes (a copy of) right side,
e.g. " <infile", short for "0<infile" means "stdin becomes infile"

c) ">file" is just short for "1>file", "<file" is short for "0<file"

d) Redirections are processed left to right.

Now piece it all together. The analogy to shell variable assignments in 
conjunction with rule d) is especially important. Look at the following:

stdout="console"
stderr="console"
html_log="html.log"
#------------- the following corresponds to 2>&1 >html.log
stderr=$stdout
stdout=$html_log

Now what will "echo $stderr" print? It should be obvious that it will 
print "console". This means that with 2>&1 >html.log, the log file will 
not receive any stderr output. It will only receive stdout output.

Compare this with the following:

stdout="console"
stderr="console"
html_log="html.log"
#------------- the following corresponds to >html.log 2>&1
stdout=$html_log
stderr=$stdout

Now what will "echo $stderr" print? Now it will print "html.log" as will 
"echo $stdout". So both stderr and stdout are sent to html.log

With this understanding you can do fancy tricks like

{ command 3>&1 1>&2 2>&3 | tee error.log ;} &>full.log

(NOTE: "&>full.log" is an abbrev. of ">full.log 2>&1")

which is the only useful way to do logging IMHO. This gives you a log with 
only the errors (so that you can quickly check using cat error.log if 
something serious went wrong) and a complete (stdout + stderr) log which 
you can use to locate an error in its proper context (in the case of a 
"make" command this would be the line that caused the error).

The following

{ command | tee stdout.log ;} &>full.log

which someone might come up with is completely useless most of the time 
because stdout.log will have everything BUT the errors (and the errors are 
usually the important info). 

MSB


----
The best time to plant a tree was 20 years ago - 

The second best is now!

-- 
Unsubscribe: send email to listar at linuxfromscratch.org
and put 'unsubscribe blfs-dev' in the subject header of the message



More information about the blfs-dev mailing list