我知道在 bash 中读取命令的基本方法:
cal | while IFS= read -r line ; do
echo X${line}X
done
但是,如果我想循环读取多个文件/命令中的一行怎么办?我尝试过命名管道,但它们只吐出一行。
$ cal > myfifo &
$ IFS= read -r line < myfifo
[cal exits]
$ echo $line
February 2015
所以我真正想要的是这样的:
while [all pipes are not done]; do
IFS=
read line1 < pipe1 # reading one line from this one
read line2 < pipe2 # and one line from this one
read line3 < pipe3 # and one line from this one
print things with $line1 $line2 and $line3
done
总体而言,我想做的是处理来自 cal 的三个不同月份的数据,进行一些着色以供 Conky 使用。老实说,这有点像刮牦牛毛,所以在这一点上已经成为学术和“学习经历”。
答案1
paste
将是最简洁的方法。但是,使用 bash 文件描述符和进程替换:
exec 3< <(cal 1 2015)
exec 4< <(cal 2 2015)
exec 5< <(cal 3 2015)
while IFS= read -r -u3 line1; do
IFS= read -r -u4 line2
IFS= read -r -u5 line3
printf "%-25s%-25s%-25s\n" "$line1" "$line2" "$line3"
done
exec 3<&-
exec 4<&-
exec 5<&-
January 2015 February 2015 March 2015
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6 7
4 5 6 7 8 9 10 8 9 10 11 12 13 14 8 9 10 11 12 13 14
11 12 13 14 15 16 17 15 16 17 18 19 20 21 15 16 17 18 19 20 21
18 19 20 21 22 23 24 22 23 24 25 26 27 28 22 23 24 25 26 27 28
25 26 27 28 29 30 31 29 30 31
答案2
您可以使用paste
组合输出,然后按行读取:
paste -d $'\n' <(foo) <(bar) <(cat baz) | while IFS= read -r line1
do
IFS= read -r line2 || break
IFS= read -r line3 || break
# ..
done
答案3
这就是您需要的结构。
您的 FIFO 位于正确的行上,但当您从中读取一行时退出的原因cal
是read -r line < myfifo
打开了 FIFO,读取了一行,然后再次关闭了它。关闭管道会向另一端发送一个信号,表明无法再进行写入(读取)操作。于是cal
退出了。
# Create the FIFOs
mknod pipe1 p
mknod pipe2 p
mknod pipe3 p
# Start off the commands
command1 >pipe1 &
command2 >pipe2 &
command3 >pipe3 &
# Attach file descriptors to the other side of the FIFOs
exec 11<pipe1 12<pipe2 13<pipe3
# Loop
IS_MORE=0
while [[ 0 eq $IS_MORE ]]
do
IS_MORE=1
read LINE1 <&11 && IS_MORE=0
read LINE2 <&12 && IS_MORE=0
read LINE3 <&13 && IS_MORE=0
# ...
done
# Close descriptors and remove the FIFOs
exec 11<&- 12<&- 13<&-
rm -f pipe1 pipe2 pipe3
# Clean up the dead processes (zombies)
wait
# ...
答案4
while \
IFS= read -r -u3 line1;do
IFS= read -r -u4 line2
IFS= read -r -u5 line3
printf "%-25s%-25s%-25s\n" "$line1" "$line2" "$line3"
done 3< <(cal -h 1 2018) 4< <(cal -h 2 2018) 5< <(cal -h 3 2018)
或者如果 3 个月是相邻的,则可能是以下内容:
while IFS= read -r;do
printf "%s\n" "${REPLY}"
done < <(cal -A 1 -B 1 -h 8 2018)