私が作成しているスクリプトの目的は、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:知っている情報を活用する
ファイルを繰り返す方法が既にわかっているので、ファイルを結合してから結合ファイルを処理できます。注文するpaste
2つのファイルを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.txt
read -ra
compareFile
while
はい
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