如何逐行处理输出并保存返回状态?

时间:2014-01-08 16:51:23

标签: bash

首先,向stackoverflow社区问好。感谢非常明确的问题和专业的回复,我学到了很多东西。我从来不需要提问,因为以前总会有人问过同样的问题。

但不是今天。我没有找到解决问题的方法,我求求你的帮助。 我需要逐行处理函数的输出,以便在线更新日志。我正在使用bash

以下块效果很好:

convertor some parameters | while read line
do
    if [ "${line:0:14}" != "[informations]" ]
    then
        update_online_log "${line}"
    fi
done

convertor可能会以不同的状态退出。我需要知道什么是退出状态。下面的代码不起作用,因为它给出了上次执行的命令(update_online_log)的退出状态。

convertor some parameters | while read line
do
    if [ "${line:0:14}" != "[informations]" ]
    then
        update_online_log "${line}"
    fi
done
exit_status=$?

下面的代码应该可以使用(我还没有尝试过):

convertor some parameters > out.txt
exit_status=$?
while read line
do
    if [ "${line:0:14}" != "[informations]" ]
    then
        update_online_log "${line}"
    fi
done < out.txt
rm out.txt

但如果我使用此功能,则会在转换结束时更新在线日志。转换可能是一个非常漫长的过程,我希望在转换过程中让用户保持更新。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

PIPESTATUS数组可能对您有所帮助:它保存了上一个管道的每个组件的退出状态:

$ (echo a; exit 42) | (cat; echo b; exit 21) | (cat; echo c; exit 3) | { cat; echo hello; }
a
b
c
hello
$ echo "${PIPESTATUS[*]}"
42 21 3 0

那个数组非常脆弱,所以如果你想用它做什么,立即把它保存到另一个数组:

$ (echo a; exit 42) | ... as above
$ ps=( "${PIPESTATUS[@]}" )
$ for i in "${!ps[@]}"; do echo "$i  ${ps[$i]}"; done
0  42
1  21
2  3
3  0

答案 1 :(得分:0)

在脚本顶部添加set -o pipefail。来自文档:

  

管道的返回值是状态                             以非零状态退出的最后一个命令,                             如果没有以非零状态退出命令,则为零

这意味着如果所有命令都成功则为零,如果任何命令失败则为非零。

只需检查done之后的退出状态即可。用

测试
convertor some parameters | false | while read line
...

不应处理任何行,退出代码应为1

答案 2 :(得分:0)

作为符合POSIX标准的解决方案,并且为了表明您的方法接近工作,您可以使用命名管道而不是常规文件。

mkfifo out.txt
while read line; do
    if [[ $line != \[informations\]* ]]; then
        update_online_log "$line"
    fi
done < out.txt &

convertor some parameters > out.txt

rm out.txt

此代码创建命名管道,然后运行在后台使用它的循环。它将阻止等待来自converter的数据。退出converter后(您可以在此时获取退出代码),out.txt将关闭,while循环进程将退出,您可以删除命名管道。