Bash: multiple redirection

At the beginning of the script, I see the following:

exec 3>&2

      

And later:

{ $app $conf_file &>$app_log_file & } 1>&3 2>&1

      

My understanding of this goes something like this:

  • Create fd 3

  • Redirect fd 3

    output tostderr

  • (After executing the application) redirect stdout

    to fd 3

    , then redirect stderr

    tostdout

Isn't this cool madness? 3

> stderr

> stdout

> 3

> Etc?

I am especially worried about the intent / consequences of this line, because I would like to start some applications using this script from valgrind

. I would like to see the output valgrind

interspersed with the application log statements, so I hope the default output stderr

is captured by the confusing line above. However, in some crashes that led me to want to use valgrind

, I saw glibc errors dumped directly to the terminal rather than written to the application log file.

So question (s): what is this execution line doing, exactly? Does it capture stderr

? If so, why am I seeing glibc output on the command line when the application crashes? If not, how can I change it to achieve this goal?

+3


source to share


2 answers


You are reading the syntax incorrectly 3>&2

. This means open fd 3 and make it a duplicate of fd 2. See Duplicating File Descriptors .

Likewise, does 2>&1

not mean that make fd 2 points to the location of fd 1, it means reopening fd 2 as a duplicate of fd 1 (basically the same network effect, but different semantics).

Also remember that all redirects happen as they occur and that there are no pointers here. So 2>&1 1>/dev/null

does not redirect standard error to /dev/null

, it leaves standard error attached to where standard output was installed (possibly a terminal).

So this code does the following:



  • Open fd 3 as duplicate of fd 2
  • Reopen fd 1 as a duplicate of fd 3
  • Reopen fd 2 as a duplicate of fd 1

Effectively these lines send everything to standard error (or wherever fd 2 was attached when the initial line was exec

executed). If there were redirects 2>&1 1>&3

, then they would be reversed. I wonder if this was the original intent of this line, since as written it is pretty pointless.

Not to mention, when redirecting inside a brace list, the redirects on the outside of the brace list are pretty useless.

+3


source


Ok, well let's see what happens in practice:

peter@tesla:/tmp/test$ bash -c 'exec 3>&2; { sleep 60m &>logfile & } 1>&3 2>&1'  > stdout 2>stderr
peter@tesla:/tmp/test$ psg sleep
peter    22147  0.0  0.0   7232   836 pts/14   S    15:51   0:00 sleep 60m
peter@tesla:/tmp/test$ ll /proc/22147/fd
total 0
lr-x------ 1 peter peter 64 Jul  8 15:51 0 -> /dev/null
l-wx------ 1 peter peter 64 Jul  8 15:51 1 -> /tmp/test/logfile
l-wx------ 1 peter peter 64 Jul  8 15:51 2 -> /tmp/test/logfile
l-wx------ 1 peter peter 64 Jul  8 15:51 3 -> /tmp/test/stderr

      

I don't know exactly why the author of your script ended up with this line of code. Apparently it made sense to them when they wrote it. Redistributions outside of curly braces occur before redirection inside, so they are both overridden with &>logfile

. Even errors from bash like this command not found

end up in the log file.



You say you see glibc messages on your terminal when the application crashes. I think your application should use fd 3

after starting it. that is, it was written to run from a script that fd opened for it 3

, otherwise it will open /dev/tty

or whatever.

BTW, psg

is the function I define in my .bashrc

:
psg(){ ps aux | grep "${@:-$USER}" | grep -v grep; }


recently updated:

psg(){  local pids=$(pgrep -f "${@:--u$USER}"); [[ $pids ]] && ps u   -p $pids; }
psgw(){ local pids=$(pgrep -f "${@:--u$USER}"); [[ $pids ]] && ps uww -p $pids; }

      

+2


source







All Articles