在bash脚本中倒退stdin [英] rewinding stdin in a bash script

查看:126
本文介绍了在bash脚本中倒退stdin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种简单的方法可以在已经从输入管道读取全部或部分内容的bash脚本中倒带" /dev/stdin?

Is there a simple way to "rewind" /dev/stdin inside my bash script which already read all or some portion from the input pipe?

应用程序:我编写了一个简单的MDA,在第1部分中,逐行从fetchmail中读取一封电子邮件,如下所示:

Application: I wrote a simple MDA that in part 1, reads a single email from fetchmail line by line, like so:

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

,在处理结束时,我希望将整个消息保存到文件中,以便进行调试,以使管道的编写器端可以看到其整个输出已被读取,而不是返回失败(因此将邮件保留为未读状态.

and at the end of processing, I wish to save the entire message into a file, both for debugging, and so that the writer-side of the pipe sees that its entire output had been read, and not return failure (therefore keeping the message as unread in the mailbox).

推荐答案

读取管道具有破坏性.无法在管道上进行搜索:

Reading a pipe is destructive; there is no way to seek on a pipe:

ESPIPE (29): Illegal seek

错误号来自MacOS X,但名称是传统名称(由POSIX规定),并指出了限制的来源.

The error number is from MacOS X, but the name is traditional (and POSIX-mandated) and gives an indication of where the restriction comes from.

因此,如果要在Shell脚本中重新处理输入,则需要将标准输入保存在文件中,以便可以对其进行重新处理:

So, if you want to reprocess input in a shell script, you will need to stash the standard input away in a file so you can reprocess it:

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

唯一要注意的陷阱是由于管道的原因,在父外壳中无法访问在while循环中设置的变量.如果有问题,可以使用:

The only trap to watch is that because of the pipeline, variables set in the while loop are not accessible in the parent shell. If that's a problem, you can use:

tee $tmp.1 |
{
while read -a linA
do
    ...
done

...reprocess $tmp.1 here...
}

花括号将语句分组以进行I/O重定向. tee进程将由于EOF而完成,因此当while read检测到EOF时文件将完成,因此可以安全地在循环后访问$tmp.1.

The braces group the statements for I/O redirection purposes. The tee process will have completed because of EOF so the file will be complete when the while read detects EOF, so it is safe to access $tmp.1 after the loop.

要注意的一件事是tee将使它对终端输入无响应.文件不会有问题;管道输入不太可能成为问题.但是,tee可能会完全缓冲其输出,而不是使用行缓冲其输出,因此在您键入很多行输入之前,读取循环可能看不到任何东西.

The one thing to watch is that tee will make this unresponsive to terminal input. Files won't be a problem; piped input is unlikely to be a problem. However, tee will probably fully buffer its output, rather than line buffering its output, so the read loop may not see anything until you've typed many lines of input.

这篇关于在bash脚本中倒退stdin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆