whileループを使用して2つの入力ファイルから読み取る方法


27

入れ子になったwhileループ内の2つの入力ファイルから1行ずつ読み取る方法があるかどうかを知りたかった。たとえば、2つのファイルFileAとがあるとしFileBます。

FileA:

[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3

FileB:

[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3

現在のサンプルスクリプト:

[jaypal:~/Temp] cat read.sh 
#!/bin/bash
while read lineA
    do echo $lineA 
    while read lineB
        do echo $lineB 
        done < fileb
done < filea

実行:

[jaypal:~/Temp] ./read.sh 
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3

問題と望ましい出力:

これは、FileAの各行に対してFileBを完全にループします。continue、break、exitを使用してみましたが、探している出力を達成するためのものではありません。スクリプトは、ファイルAから1行、次にファイルBから1行だけを読み取ってループを終了し、ファイルAの2行目とファイルBの2行目から続行したいと思います。次のスクリプトに似たもの-

[jaypal:~/Temp] cat read1.sh 
#!/bin/bash
count=1
while read lineA
    do echo $lineA 
        lineB=`sed -n "$count"p fileb`
        echo $lineB
        count=`expr $count + 1`
done < filea

[jaypal:~/Temp] ./read1.sh 
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3

whileループでこれを達成することは可能ですか?


@codaddictの優れたソリューションはこちらです:stackoverflow.com/a/4011824/4095830- >paste -d '\n' file1 file2
whoan

回答:


32

最初のファイルに文字が出現しないことが確実にわかっている場合は、貼り付けを使用できます。

デフォルトの区切りタブを使用した貼り付けの例:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

を使用した貼り付けの例@

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

文字が最初のファイルで発生しないことが保証されていれば十分であることに注意してください。これは、最後の変数を埋めるときreadに無視さIFSれるためです。その@ため、2番目のファイルで発生しても、分割されません。

ほぼ間違いなくコードにいくつかのbash機能を使用した貼り付けの例:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

使用されるBash機能:ansi c文字列$'\t')およびプロセス置換<(...)サブシェルの問題でwhileループ回避します

両方のファイルで文字が発生しないことを確信できない場合は、ファイル記述子を使用できます

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

あまりテストされていません。空行で中断する場合があります。

ファイル記述子番号0、1、および2は、それぞれstdin、stdout、およびstderrにすでに使用されています。3以降のファイル記述子は(通常)無料です。bashマニュアルは、9を超えるファイル記述子は「内部的に使用される」ため、使用しないように警告しています。

開いているファイル記述子は、シェル関数と外部プログラムに継承されることに注意してください。開いているファイル記述子を継承する関数およびプログラムは、ファイル記述子から読み取り(および書き込み)できます。関数または外部プログラムを呼び出す前に、不要なファイル記述子をすべて閉じてください。

上記と同じプログラムで、実際の作業(印刷)をメタ作業(2つのファイルから1行ずつ並行して読み取る)から分離しています。

work() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

ここで、作業コードを制御できず、そのコードが何らかの理由でファイル記述子3から読み取ろうとするふりをします。

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

出力例を次に示します。最初のファイルの2行目はループから「盗まれた」ことに注意してください。

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

以下は、外部コード(またはそのことに関するコード)を呼び出す前にファイル記述子を閉じる方法です。

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing anycode
  anycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

17

異なるファイル記述子で 2つのファイルを開きますread組み込みの入力を、目的のファイルが接続されている記述子にリダイレクトします。bash / ksh / zshでは、のread -u 3代わりに書くことができますread <&3

while IFS= read -r lineA && IFS= read -r lineB <&3; do
  echo "$lineA"; echo "$lineB"
done <fileA 3<fileB

このスニペットは、最短のファイルが処理されると停止します。2つのファイルをIFS whileループに読み込むを参照してください-この場合、diffの結果をゼロにする方法はありますか?両方のファイルの終わりまで処理を続けたい場合。

参照してくださいあなたは、追加のファイル記述子を使用する場合は?ファイル記述子の追加情報、および`IFS =の代わりに` while IFS = read`が頻繁に使用される理由 読みながら..`?の説明についてはIFS= read -r


ファイル記述子の追加リンクをありがとう@Gilles。
ジャイパルシン

@Gillesおそらく私はあなたを誤解したかもしれませんが、ループ処理を最長ファイル(この場合は常に$ fileA)にすることはできませんでしたので、それを別の質問に作りました:その差分は、入力と出力の違いに気づきませんか?unix.stackexchange.com/questions/26780/…一番近いのはdiffで、1行の違いしか見つけられませんでした。
ixtmixilix


2

以下のコマンドを試してください:

paste -d '\n' inp1.txt inp2.txt > outfile.txt

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.