[英]rewinding stdin in a bash script
Is there a simple way to "rewind" /dev/stdin
inside my bash script which already read all or some portion from the input pipe? 有没有一种简单的方法可以在我的bash脚本中“倒带”
/dev/stdin
,该脚本已经从输入管道中读取了全部或部分内容?
Application: I wrote a simple MDA that in part 1, reads a single email from fetchmail line by line, like so: 应用程序:我编写了一个简单的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
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
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. 错误号来自MacOS X,但名称是传统名称(由POSIX规定),并指出了限制的来源。
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: 因此,如果要在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
The only trap to watch is that because of the pipeline, variables set in the while
loop are not accessible in the parent shell. 唯一需要注意的陷阱是由于管道的原因,
while
循环中设置的变量无法在父外壳中访问。 If that's a problem, you can use: 如果有问题,可以使用:
tee $tmp.1 |
{
while read -a linA
do
...
done
...reprocess $tmp.1 here...
}
The braces group the statements for I/O redirection purposes. 花括号将语句分组以用于I / O重定向。 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
进程将由于EOF而完成,因此当while read
检测到EOF时文件将完成,因此可以安全地在循环后访问$tmp.1
。
The one thing to watch is that tee
will make this unresponsive to terminal input. 要注意的一件事是,
tee
将使其对终端输入无响应。 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. 但是,
tee
可能会完全缓冲其输出,而不是使用行缓冲其输出,因此在您键入很多行输入之前,read循环可能看不到任何内容。
尝试exec < /dev/stdin
,它可能在Linux下工作。
Not really, no. 不是,不是
You'll just have to append each line into a variable as you read it and clear the variable as needed. 您只需在阅读时将每行追加到变量中,然后根据需要清除该变量。
how about: 怎么样:
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
I think it's better way because you read message just once 我认为这是更好的方法,因为您只阅读了一次消息
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.