在 bash 脚本中重绕 stdin [英] rewinding stdin in a bash script

查看:20
本文介绍了在 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?

应用程序:我在第 1 部分中编写了一个简单的 MDA,它逐行读取来自 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]:	${#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

唯一需要注意的陷阱是由于管道的原因,在父 shell 中无法访问 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天全站免登陆