我有以下代码,它读取许多命令,打印它们并打印它们的输出。
while read line ; do
echo "C:$line"
echo "O:$(${line} 2>&1 | perl -pe 's,\n,\\n,'g)\n"
done << EOF
g++-4.8 -O2 -Wall -Wextra -pedantic -pthread main.cpp
./a.out
EOF
输出:
C:g++-4.8 -O2 -Wall -Wextra -pedantic -pthread main.cpp
O:main.cpp: In function ‘int main(int, char**)’:\nmain.cpp:3:9: warning: unused variable ‘unused’ [-Wunused-variable]\n int unused;\n ^\n\n
C:./a.out
O:*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff3bd01a5c ***\n======= Backtrace: =========\n/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f6960e1ab96]\n./a.out[0x400502]\n/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f6960dbd76d]\n./a.out[0x400535]\n======= Memory map: ========\n\n
我想区分stdout和stderr并使用stderr的'E:'前缀。另外我想打印每个命令行的退出代码。
我怎样才能做到这一点?
答案 0 :(得分:10)
#!/bin/bash
# Add a prefix to each line of stdin.
prefix() {
local line
while read line; do printf '%s%s\n' "$1" "$line"; done
}
# Execute each command. Notice the `(' and `)' surrounding the loop body, which starts
# a sub-shell for each iteration. Running in a sub-shell lets us use `trap EXIT' to
# cleanup.
while read command; do (
# Create FIFOs for the command's stdout and stderr.
stdout=$(mktemp -u)
stderr=$(mktemp -u)
mkfifo "$stdout" "$stderr"
# Delete the FIFOs when this iteration of the loop finishes. Use `trap' to ensure
# cleanup happens whether we finish normally or are signalled.
trap 'rm -f "$stdout" "$stderr"' EXIT
# Read from the FIFOs in the background, adding the desired prefixes.
prefix 'O:' < "$stdout" >&1 &
prefix 'E:' < "$stderr" >&2 &
# Now execute the command, sending its stdout and stderr to the FIFOs.
echo "C:$command"
eval "$command" 1> "$stdout" 2> "$stderr"
exitcode=$?
# Wait for the `prefix' processes to finish, then print the exit code.
wait
echo "R:$exitcode"
exit $exitcode
) done
答案 1 :(得分:1)
这是我提交的内容。我认为它与John的相似,但似乎有一些更少的线条。我只是将它作为替代方案包含在这里,因为我遇到了类似的问题,并且想要尝试确定更紧凑的解决方案。
我认为此问题的主要原因是管道|
运营商不允许您指定与重定向相关的流类似的流,例如2>
。
我在这里得到的解决方案是将多个子shell的输出链接在一起,内部处理stdout
,然后将其重定向到备用临时流3
。
下一个子shell再次将stderr
重定向到stdin
并重复内壳的活动(尽管前缀为&#34; E:&#34; 而不是的&#34,O:&#34; 强>)。它会再次将输出重定向到stdout
,但如果您希望将所有内容都包含在>&2
中,则可以删除stdin
(但我认为保持这些流是分开的)优势)。
外壳再次与&3
重新加入stdin
流。
由于两个内壳分别处理stdin
和stdout
(因为替代&#34; O:&#34;和&#34; E:&#34;前缀)有必要运行perl
命令两次,所以我将它包装到fold
函数中以保持整洁,这也是添加不同前缀的地方。
您可能会取消使用sed
并将其包含在perl
正则表达式中,并且还要注意\\n
在每行末尾引入perl
function fold {
perl -pe 's,\n,\\n,'g | sed 's/^\(.*\)$/'${1}':\1\n/'
}
while read line ; do
echo "C:$line"
(
(
${line} | fold O >&3
) 2>&1 | fold E >&2
) 3>&1
done
1}}命令。事实上,我个人的观点是,这个命令引入的折线现在不应该是必要的,但我保留它以保持原始问题的真实性。
{{1}}