Bash:多redirect

在脚本的早期,我看到这个:

exec 3>&2 

然后:

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

我对此的理解如下所示:

  • 创buildfd 3
  • 将fd 3输出redirect到stderr
  • (在应用程序执行时)将stdoutredirect到fd 3 ,然后将stderrredirect到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它将标准错误附加到标准输出附加到的位置 (可能是终端)。

所以有问题的代码这样做:

  1. 打开fd 3作为fd 2的副本
  2. 重新打开fd 1作为fd 3的副本
  3. 重新打开fd 2作为fd 1的副本

有效地,这些行将所有内容发送到标准错误(或者在初始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; }