在BASH中使用PIPESTATUS有什么问题?

时间:2010-10-03 21:36:41

标签: linux bash pipe

我有一个for循环,我通过ssh传递给服务器,其格式看起来像这样......

i=0
for cmd in cmd_list;
do ${cmd} | sed "s/^/OUTPUT_${i}_: /" &
(( i++ ));
done;
wait

这个想法是for循环将运行我给它的命令列表并将每个命令管道输入sed,其中sed在每个输出行前面加上一个命令编号(0,1,2,3等等... )。然后是背景,以便允许并行执行。这使我能够跟踪输出与哪个命令相关联,因为数据可以同时返回并且全部混淆。这非常有效。根据命令打印信息的时间和完成时间,输出可能看起来像这样......

OUTPUT_0_: some_data_string_from_a_command
OUTPUT_2_: some_data_string_from_a_command
OUTPUT_0_: some_data_string_from_a_command
OUTPUT_3_: some_data_string_from_a_command
OUTPUT_1_: some_data_string_from_a_command
OUTPUT_1_: some_data_string_from_a_command

然而,我真正想做的是......

do ${cmd} 2>&1 | sed "s/^/OUTPUT_${i}_${PIPESTATUS[0]}: /" &

所以我可以回来......

OUTPUT_0_0: some_data_string_from_a_command
OUTPUT_2_1: some_error_message_from_a_command
OUTPUT_0_0: some_data_string_from_a_command
OUTPUT_3_1: some_error_message_from_a_command
OUTPUT_1_0: some_data_string_from_a_command
OUTPUT_1_0: some_data_string_from_a_command

如果第一个命令出错,这可以正常工作。我通常会从$ {PIPESTATUS [0]}获得非零退出代码。但是,当我故意在列表中进一步种植命令时,我知道这些命令会失败(即cat / tmp / some_non_existent_file),PIPESTATUS不会在管道链中给出正确的命令退出代码。我有时会得到0而不是真正的退出代码。

知道为什么会这样吗?

1 个答案:

答案 0 :(得分:2)

管道中的命令是并行执行的。这意味着它们可能在您评估PIPESTATUS时没有退出,特别是因为在实际运行sed命令之前PIPESTATUS由shell扩展。

我真的不明白你想要做什么,因为你似乎想要违反因果关系。你仔细想过吗?您似乎希望命令的退出值及其输出,但如果它正在输出数据,则它显然没有退出。你一直在打开一个小的计时窗口。它可能适用于某些短期运行时命令,但这甚至是有问题的,因为在没有同步操作的情况下协调并行执行很容易发生“随机”故障。

如果要捕获数据以及命令的输出状态,则需要将输出保存到某处(例如在文件中),并且当进程退出时,然后使用退出输出数据状态。