2つのファイルの行を通る並列ループ[閉じる]

2つのファイルの行を通る並列ループ[閉じる]

私が作成しているスクリプトの目的は、2つのファイルシリーズを比較することです。ファイル名自体は、2つの別々のファイルに1行に1つずつ格納されます。私の考えは、それぞれファイル名のリストに対応する2つのループを持つことですwhile read。しかし、これらの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つのwhile readループを介して2つの異なるリストにあるファイルを同時に比較できる必要があります。これは可能ですか?

答え1

2つのループは必要ありません。 1つのループで両方のファイルを読み取るだけです。

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

方法1:知っている情報を活用する

ファイルを繰り返す方法が既にわかっているので、ファイルを結合してから結合ファイルを処理できます。注文するpaste2つのファイルを1行ずつリンクします。 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あるファイルの空白行を別のファイルの空でない行と一致させることができるため、各ファイルで個別にこれを行う必要があります。これを使用して、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つの部分に分けることです。つまり、ファイル内の空白行をスキップし、空でない行を処理することです。空行をスキップする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回呼び出す必要があるため、これを行うための最良の方法です。関数では、valueという変数の値を計算する${!#}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

答え3

1つの方法read -raは、2つの列があり、それぞれファイル名があると仮定するreadと、両方の列を読み取り、配列に割り当て、ループを介してインデックス0が使用されるようにすることです。最初のファイルとインデックス1は2番目のファイルになります。filestoCompare.txtread -racompareFilewhile

はい

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

リスト1と2の内容は次のとおりです。

$ cat list1and2
file1   file4
file2   file5
file3   file6

関連情報