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

Bash 如何逐行处理输出并保存返回状态?,bash,Bash,首先,大家好,stackoverflow社区。我学到了很多,这要感谢非常清晰的问题和专业的回答。我从来不需要问问题,因为总有人问过同样的问题 但今天不行。我还没有找到解决我问题的办法,我请求你的帮助。 我需要逐行处理函数的输出,以便在线更新日志。我正在使用bash 下面的块工作得很好: convertor some parameters | while read line do if [ "${line:0:14}" != "[informations]" ] then

首先,大家好,stackoverflow社区。我学到了很多,这要感谢非常清晰的问题和专业的回答。我从来不需要问问题,因为总有人问过同样的问题

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

下面的块工作得很好:

convertor some parameters | while read line
do
    if [ "${line:0:14}" != "[informations]" ]
    then
        update_online_log "${line}"
    fi
done
但是,
转换器
可能以不同的状态退出。我需要知道什么是退出状态。下面的代码不起作用,因为它提供了上次执行的命令的退出状态(
update\u online\u log

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

转换器某些参数>out.txt
退出状态=$?
读行时
做
如果[“${line:0:14}”!=“[信息]”]
然后
更新联机日志“${line}”
fi
done
但是如果我使用这个,在线日志将在转换结束时更新。转换可能是一个很长的过程,我希望在转换过程中不断更新用户


提前感谢您的帮助。

在脚本顶部添加
set-o pipefail
。从文件中:

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

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

只要在
完成后检查退出状态就可以了。测试一下

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

不应处理任何行,并且退出代码应为
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

作为与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
mkfifo out.txt
读行时;做
如果[[$line!=\[informations\]*];然后
更新联机日志“$line”
fi
doneout.txt
rm out.txt

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

请看哇,这太快了!非常感谢,这正是我所需要的!这正是我想要的。谢谢:)
$ (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
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