2つのファイルの行を並行してループする[終了]


18

私が作成しているスクリプトの目的は、2つのシリーズのファイルを比較することです。ファイル名自体は、1行に1つのパスを持つ2つの個別のファイルに保存されます。私のアイデアはwhile read、ファイル名のリストごとに1つずつ、2つのループを作成することですが、2つのループをどのように混在させることができますか?

while read compareFile <&3; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile" _(other file from loop?_) >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt

読み取りループ中に2つの異なるリストのファイルを同時に2つ比較できるようにする必要があります...これは可能ですか?


このスクリプトを挑戦の王様にするつもりですか?そうでない場合は、ファイルを比較するための強力なツールが既に存在しますdiff
lgeorget

一種の挑戦の」、申し訳ありません
lgeorget

OPが使用してdiffいる@lgeorget 。
テルドン

ああ、2つのリストからのファイル。無駄なコメントでごめんなさい...
lgeorget

クロスポストを避けてください
iruvar

回答:


20

2つのループは必要ありません。1つのループで2つのファイルから読み取る必要があります。

while read compareFile1 <&3 && read compareFile2 <&4; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile1" "$compareFile2" >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt 4<other_file

コードのおかげでコードが減りました!空の行の例外を2つのループで同時に処理するにはどうすればよいですか?
mkrouse

@mkrouse、以前にその$ server変数で何をしていたのかわかりませんが、1つの変数で空の行をテストしても、他の変数で同じことを行うだけです
...-psusi

7

方法1:知っていることを使用する

1つのファイルをループする方法を既に知っているので、ファイルを結合して、結合したファイルを処理できます。このコマンドpasteは、2つのファイルを行ごとに結合します。2つのファイルからの行の間にタブを配置するため、このソリューションでは、ファイル名にタブがないことを前提としています。(区切り文字は変更できますが、ファイル名に存在しない文字を見つける必要があります。)

paste -- "$list1.txt" "list2.txt" |
while IFS=$'\t' read -r file1 file2 rest; do
  diff -q -- "$file1" "$file2"
  case $? in
    0) status='same';;
    1) status='different';;
    *) status='ERROR';;
  esac
  echo "$status $file1 $file2"
done

空白行をスキップする場合は、各ファイルで個別に行う必要がありますpaste。1つのファイルの空白行と別のファイルの非空白行が一致する可能性があるためです。使用できますgrepして、非空白行をフィルタリング。

paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
  

2つのファイルの長さが異なる場合は、空になることに注意してください $file2(どちらのリストが最初に終了したかに関係なく)。

方法2:2つのファイルをループする

whileループの状態に好きなだけ複雑なコマンドを入れることができます。配置read file1 <&3 && read file2 <&4すると、両方のファイルに読み込む行がある限り、つまり1つのファイルがなくなるまでループが実行されます。

while read -u 3 -r file1 && read -u 4 -r file2; do
  
done 3<list1..txt 4<list2.txt

空白行をスキップする場合、2つのファイルを個別にスキップする必要があるため、少し複雑になります。簡単な方法は、問題を2つの部分に分けることです。1つのファイルから空白行をスキップし、非空白行を処理します。空白行をスキップする1つの方法はgrep、上記のように処理することです。<リダイレクト演算子と<(コマンドの中断を開始する演算子の間の必要なスペースに注意してください。

while read -u 3 -r file1 && read -u 4 -r file2; do
  
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")

別の方法は、read空行をスキップするように動作する関数を作成することです。この関数はread、ループで呼び出すことで機能します。関数である必要はありませんが、関数を使用するのが最良の方法です。コードを整理するためと、そのコードを2回呼び出す必要があるためです。関数で${!#}は、bash構造のインスタンスで、${!VARIABLE}名前がの値である変数の値に評価されVARIABLEます。ここで、変数は#位置パラメータの数を含む特別な変数で${!#}あり、最後の位置パラメータも同様です。

function read_nonblank {
  while read "$@" &&
        [[ ${!#} !~ [^[:space:]] ]]
  do :; done
}
while read_nonblank -u 3 -r file1 && read_nonblank -u 4 -r file2; do
  
done 3<list1..txt 4<list2.txt

読み取り-uオプションの使用が好きです
フェリペアルバレス

1

1つのアプローチはread -raただの代わりに使用することでしょうreadfilestoCompare.txtそれぞれにファイル名を持つ2つの列が含まれると仮定すると、はread -ra両方の列を同時に読み取り、配列に割り当てますcompareFile。この配列にアクセスすると、whileループを実行するたびに、インデックス0が最初のファイルになり、インデックス1が2番目のファイルになります。

このファイルがあるとします:filestoCompare.txt、次が含まれています:

file1 file2
file3 file4
file5 file6

このファイルを調べるコマンドは次のとおりです。

$ while read -ra a ; do printf "%s\t%s\n" ${a[0]} ${a[1]}; done < filestoCompare.txt
file1   file2
file3   file4
file5   file6

2つのファイルが実際に次のような個別のファイルである場合:

#list1
file1
file2
file3

#list2
file4
file5
file6

これらはpaste次のようなコマンドで結合できます。

$ paste list1 list2 > list1and2

list1and2の内容は次のとおりです。

$ cat list1and2
file1   file4
file2   file5
file3   file6

しかし、それは入力形式ではありません。リストは2つの異なるファイルにあります。join最初にできます。
ジル 'SO-悪であるのをやめる'

@Gilles-それが入力形式ではないことは知っています。「... filestoCompare.txtにはそれぞれにファイル名のある2つの列が含まれていると仮定して...」と言ったと思います。私はあなたの主張を理解しており、同意しません。OPは、この質問を投稿して以来、この質問に関するガイダンスを提供していません。
slm

@Gilles-コマンドpasteを使用して2つのファイルを結合する方法を示す例を追加するとどうなりますか?それであなたは投票権を取り消すことができますか?
slm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.