是否有一种简单的方法可以在我的bash脚本中“回放”/dev/stdin
,该脚本已经从输入管道中读取了全部或部分内容?
应用程序:我写了一个简单的MDA,在第1部分中,逐行读取来自fetchmail的单个电子邮件,如下所示:
while read -a linA; do
echo -e "$[++linenum]:\t${#linA[@]},${linA[*]}" > /dev/null # verbose
[ "${linA[0]}" = "Date:" ] && unset linA[0] && mailDate="${linA[*]}"
[ "${linA[0]}" = "Subject:" ] && unset linA[0] && mailSubject="${linA[*]}"
[ "$mailSubject" = "Courtesy Fill Notification" ] || break # if wrong subject then thank you, we're done with this mail
done
并且在处理结束时,我希望将整个消息保存到一个文件中,用于调试,以便管道的编写者端看到它的整个输出已被读取,而不是返回失败(因此将邮件保留为邮箱中的未读邮件。)
答案 0 :(得分:5)
读管是破坏性的;没有办法寻找管道:
ESPIPE (29): Illegal seek
错误编号来自MacOS X,但名称是传统的(并且是POSIX强制的),并指示限制的来源。
因此,如果您想在shell脚本中重新处理输入,则需要将标准输入存储在文件中,以便您可以重新处理它:
tmp=${TMPDIR:-/tmp}/xx.$$ # Consider mktemp or something
trap "rm -f $tmp.1; exit 1" 0 1 2 3 13 15 # Exit, HUP, INT, QUIT, PIPE, TERM
tee $tmp.1 |
while read -a linA
do
...
done
...reprocess $tmp.1 here...
rm -f $tmp.1
trap 0
exit $exit_status
唯一需要注意的陷阱是,由于管道,父shell中无法访问while
循环中设置的变量。如果这是一个问题,您可以使用:
tee $tmp.1 |
{
while read -a linA
do
...
done
...reprocess $tmp.1 here...
}
大括号将语句分组以进行I / O重定向。由于EOF,tee
进程已完成,因此当while read
检测到EOF时文件将会完整,因此在循环后访问$tmp.1
是安全的。
要注意的一件事是tee
会使终端输入无响应。文件不会有问题;管道输入不太可能成为问题。但是,tee
可能会完全缓冲其输出,而不是对其输出进行行缓冲,因此在您键入多行输入之前,读取循环可能看不到任何内容。
答案 1 :(得分:0)
不是,不。
您只需在阅读时将每一行附加到变量中,并根据需要清除变量。
答案 2 :(得分:0)
怎么样:
tmpfile=$(mktemp)
while read -a linA; do
echo -e "$[++linenum]:\t${#linA[@]},${linA[*]}" > /dev/null # verbose
[ "${linA[0]}" = "Date:" ] && unset linA[0] && mailDate="${linA[*]}"
echo "${linA}">>$tmpfile
done
mv $tmpfile fulltext.txt
我认为这是更好的方式,因为你只读过一次消息
答案 3 :(得分:0)
尝试可能在Linux下运行的exec < /dev/stdin
。