Bashで一度に1行ずつ複数のファイルを読み込む

Bashで一度に1行ずつ複数のファイルを読み込む

私はBashからコマンドを読み取る基本的な方法を知っています。

cal | while IFS= read -r line ; do 
    echo X${line}X
done

しかし、ループ内の複数のファイル/コマンドから1行を読むにはどうすればよいですか?名前付きパイプを試してみましたが、1行だけ吐きました。

$ 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のデータを3ヶ月間処理し、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出力を結合してから1行ずつ読み取ることができます。

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が正しいラインにありますが、ラインを読み取ると終了するのは、FIFOを開いてラインを読み、再び閉じたためcalです。read -r line < myfifoパイプを閉じると、もう書き込み(読み取り)操作が不可能であるという信号をもう一方の端に送信します。だから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)

関連情報