在脚本的早期,我看到了这一点:
exec 3>&2
后来:
{ $app $conf_file &>$app_log_file & } 1>&3 2>&1
我对此的理解看起来像这样:
3
3
输出重定向至stderr
stdout
重定向到fd 3
,然后将stderr
重定向到stdout
这不是某种循环的疯狂吗? 3
> stderr
> stdout
> 3
>等等
我特别关注此行的意图/含义,因为我想使用此脚本valgrind
开始运行一些应用程序。我希望看到valgrind
的输出穿插了应用程序的日志语句,所以我希望上面的混乱行捕获stderr
的默认输出。但是,在导致我想要使用valgrind
的一些崩溃中,我看到glibc错误直接输出到终端,而不是在应用程序的日志文件中捕获。
所以,问题:那条执行线究竟做了什么?它是否捕获stderr
?如果是这样,为什么当应用程序崩溃时我在命令行上看到glibc输出?如果没有,我应该如何改变它以实现这一目标?
答案 0 :(得分:4)
您误读了3>&2
语法。这意味着打开fd 3并使其成为fd 2的副本。请参阅Duplicating File Descriptors。
同样2>&1
不意味着使fd 2指向fd 1的位置,这意味着重新打开fd 2作为fd 1的副本(大多数是相同的网络)效果,但不同的语义)。
还要记住,所有重定向都会在它们发生时发生,并且没有"指针"这里。因此2>&1 1>/dev/null
不将标准错误重定向到/dev/null
它会将标准错误附加到标准输出附加到(可能是终端)的位置。
所以有问题的代码会这样做:
实际上,这些行会将所有内容发送到标准错误(或者在初始exec
行运行时附加fd 2的位置)。如果重定向是2>&1 1>&3
,那么他们就会交换位置。我想知道这是否是该行的初衷,因为正如所写,这是毫无意义的。
更不用说使用重定向 in 大括号列表,大括号列表外部的重定向是相当无用的。
答案 1 :(得分:2)
好的,让我们看看实践中会发生什么:
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
我不确定您脚本的作者究竟为何会以这行代码结束。据推测,当他们写作时,这对他们来说是有意义的。大括号外的重定向发生在内部重定向之前,因此它们都被&>logfile
覆盖。即使来自bash的错误,如command not found
也会在日志文件中结束。
您说当应用崩溃时,您会在终端上看到glibc消息。我认为您的应用在启动后必须使用fd 3
。即,它是从为其打开fd 3
的脚本开始编写的,否则会打开/dev/tty
或其他内容。
BTW,psg
是我在.bashrc
中定义的函数:
psg(){ ps aux | grep "${@:-$USER}" | grep -v grep; }
最近更新为:
psg(){ local pids=$(pgrep -f "${@:--u$USER}"); [[ $pids ]] && ps u -p $pids; }
psgw(){ local pids=$(pgrep -f "${@:--u$USER}"); [[ $pids ]] && ps uww -p $pids; }