私が作成しているスクリプトの目的は、2つのシリーズのファイルを比較することです。ファイル名自体は、1行に1つのパスを持つ2つの個別のファイルに保存されます。私の考えは、2つのwhile read
ループ、ファイル名のリストごとに1つですが、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読み取りループを介して、2つの異なるリストのファイルを同時に比較できるようにする必要があります...これは可能ですか?
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
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
が返されます(どのリストが最初に終了したかに関係なく)。
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回呼び出す必要があるため、関数は最良のアプローチです。関数では、${!#}
は、名前がVARIABLE
の値である変数の値に評価されるbash構文${!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
1つのアプローチは、read -ra
だけではなくread
。 filestoCompare.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