在脚本的早期,我看到这个:
exec 3>&2
然后:
{ $app $conf_file &>$app_log_file & } 1>&3 2>&1
我对此的理解如下所示:
3
3
输出redirect到stderr
stdout
redirect到fd 3
,然后将stderr
redirect到stdout
这不是一种圆形的疯狂吗? 3
> stderr
> stdout
> 3
>等?
我特别关心这一行的意图/含义,因为我想用valgrind
使用这个脚本开始运行一些应用程序。 我想看看valgrind
的输出与应用程序的日志语句散布,所以我希望stderr
的默认输出被上面的混淆行捕获。 然而,在一些导致我想要使用valgrind
的崩溃中,我看到glibc错误直接输出到terminal,而不是在应用程序的日志文件中捕获。
那么,问题是:执行线究竟做了什么? 它捕获stderr
吗? 如果是这样,为什么当应用程序崩溃时,在命令行上看到glibc输出? 如果不是,我应该如何改变它来完成这个目标?
你误读了3>&2
语法。 这意味着打开fd 3并使其成为fd 2的副本。请参阅复制文件描述符 。
以同样的方式2>&1
并不意味着使fd 2指向fd 1的位置,这意味着重新打开fd 2作为fd 1的重复(大部分是相同的净效果,但不同的语义)。
还要记住,所有的重定向都是在发生的时候发生的,而且这里没有“指针”。 因此, 2>&1 1>/dev/null
不会将标准错误重定向到/dev/null
它将标准错误附加到标准输出附加到的位置 (可能是终端)。
所以有问题的代码这样做:
有效地,这些行将所有内容发送到标准错误(或者在初始exec
线路运行时连接fd 2的地方)。 如果重定向是2>&1 1>&3
那么他们将会交换位置。 我想知道这是否是这个意思,因为正如所写的那样,这是毫无意义的。
更不用说,使用括号列表中的重定向,括号列表外部的重定向是相当无用的。
好的,让我们看看在实践中会发生什么:
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
或者其他东西。
顺便说一句, 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; }