open MAKE, "command 2>&1 |" or die;
open (LOGFILE, ">>some.log") or die;
while (<MAKE>) {
print LOGFILE $_;
print
}
close MAKE; # To get $?
my $exit = $? >> 8;
close LOGFILE;
#!/bin/bash
tee_args=()
while [[ $# > 0 && $1 != -- ]]; do
tee_args=("${tee_args[@]}" "$1")
shift
done
shift
# now ${tee_args[*]} has the arguments before --,
# and $* has the arguments after --
# redirect standard out through a pipe to tee
exec | tee "${tee_args[@]}"
# do the *real* exec of the desired program
exec "$@"
9条答案
按热度按时间w8biq8rn1#
这适用于Bash:
圆括号的作用是将pipefail限制在一个命令中。
从bash(1) man page:
除非启用了
pipefail
选项,否则管道的返回状态是最后一个命令的退出状态。如果启用了pipefail
,则管道的返回状态是要以非零状态退出的最后一个(最右侧)命令的值,如果所有命令都成功退出,则返回状态为零。kyvafyod2#
我在 * Capture Exit Code Using Pipe & Tee * 上偶然发现了一些有趣的解决方案。
disho6za3#
这是一个
eet
,适用于我手头上的所有Bash,从2.05b到4.0。(
pipefail
和$PIPESTATUS
很不错,但我记得它们是在Python 3.1左右引入的。)bd1hkmkf4#
这是我认为最好的纯Bourne shell解决方案,可以用作构建“eet”的基础:
我认为这最好从里到外解释-
command1
将执行并在stdout(文件描述符1)上打印其常规输出,然后一旦完成,echo
将执行并在其stdout上打印command1
的退出代码,但该stdout被重定向到文件描述符3。当
command1
运行时,其stdout通过管道传输到command 2(echo
的输出从未到达command 2,因为我们将其发送到文件描述符3而不是管道读取的文件描述符1)。然后我们将command2
的输出重定向到文件描述符4,因此它也不属于文件描述符1-因为我们希望在将文件描述符3上的echo
输出返回到文件描述符1时清除文件描述符1,以便命令替换(反勾号)可以捕获它。最后一点神奇之处是我们第一次把
exec 4>&1
作为一个单独的命令--它把文件描述符4作为一个外部shell的stdout的副本打开。命令替换将从标准输出中的命令的Angular 捕获写在标准输出上的任何内容--但是,由于就命令替换而言,command2
的输出将指向文件描述符4,命令替换并没有捕获它--然而,一旦它从命令替换中“出来”,它实际上仍然会转到脚本的整个文件描述符1。(The
exec 4>&1
必须是一个单独的命令才能与许多常见的shell一起工作。在一些shell中,如果你只是把它放在变量赋值的同一行上,在替换的结束反勾之后,它就可以工作。)(我在示例中使用了复合命令(
{ ... }
),但是subshell(( ... )
)也可以工作。subshell只会导致子进程的冗余forking和wait,因为管道的每一端和命令替换的内部通常都暗示了子进程的fork和wait。我不知道有哪个shell被编码为可以跳过其中一个分支,因为它已经完成或将要完成另一个分支。)您可以用一种技术性较低、更有趣的方式来看待它,就好像命令的输出是相互跳跃的:
command1
通过管道传送到command2
,然后echo
的输出跳过command2
使得command2
不捕捉它,然后command2
的输出跳过并跳出命令替换,就在echo
刚好及时到达以被替换捕捉使得它在变量中结束时,并且command2
的输出继续其到标准输出的路径,就像在普通管道中一样。另外,据我所知,在这个命令的末尾,
$?
仍然包含管道中第二个命令的返回代码,因为变量赋值、命令替换和复合命令对于它们内部命令的返回代码都是透明的,所以command2
的返回状态应该传播出去。需要注意的是,
command1
可能会在某个时候使用文件描述符3或4,或者command2
或后面的任何命令将使用文件描述符4,因此为了更卫生,我们可以这样做:命令从启动它们的进程中继承文件描述符,因此整个第二行将继承文件描述符4,而
3>&1
后面的复合命令将继承文件描述符3,因此4>&-
确保内部复合命令不会继承文件描述符4。并且3>&-
确保command1
不会继承文件描述符3,因此command 1得到了一个“更干净”、更标准的环境。您还可以将内部的4>&-
移到3>&-
旁边,但我想为什么不尽可能地限制它的范围。几乎没有程序直接使用预先打开的文件描述符3和4,所以您几乎不必担心它,但后者可能是最好记住并用于通用情况。
bmp9r5qi5#
pbgvytdp6#
KornShell,* 全部 * 在一行中:
inkz8wg97#
我还在寻找一个在AppleScript中
do shell script
下运行的一行程序,它总是使用/bin/sh(由zsh模拟)。这个版本是我发现的唯一一个运行良好的版本:或在AppleScript中
xdnvmnnf8#
希望这对你有用。
rslzwgfq9#
假设Bash或Z壳(
zsh
),注意:将标准误差重定向和复制到标准输出的顺序是非常重要的!
我没有意识到你也想在屏幕上看到输出。这当然会将所有输出定向到文件 my_log。