したがって、デフォルトでは、作業ディレクトリ(file.00.txtからfile.24.txtという名前)で特定のファイルを特定するためにbashスクリプトを作成する必要があります。問題は、そのうちの3つが同じであるということです。私の使命は、どの3つが同じかを示すスクリプトを作成することです。
これは私のコードです
#!/bin/bash
f0=file.00.txt
f1=file.01.txt
f2=file.02.txt
f3=file.03.txt
f4=file.04.txt
f5=file.05.txt
f6=file.06.txt
f7=file.07.txt
f8=file.08.txt
f9=file.09.txt
f10=file.10.txt
f11=file.11.txt
f12=file.12.txt
f13=file.13.txt
f14=file.14.txt
f15=file.15.txt
f16=file.16.txt
f17=file.17.txt
f18=file.18.txt
f19=file.19.txt
f20=file.20.txt
f21=file.21.txt
f22=file.22.txt
f23=file.23.txt
f24=file.24.txt
array=($f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15 $f16 $f17 $f18 $f19 $f20 $f21 $f22 $f23 $f24)
i=0
touch placeholder
while [ $i -lt ${#array} ]
do
DIFF=$(diff ${array[i]} ${array[i+1]})
if [ "$DIFF" = "" ]
then
echo "${array[i]} y ${array[i+1]}" >> placeholder
fi
i=$((i+1))
done
cat placeholder
このコードのアイデアは、各ファイルを配列内の次のファイルと比較し、同じファイルをプレースホルダと呼ばれるファイルに保存し、最後にcatコマンドを使用してファイルの内容を表示することです。
ただし、スクリプトを実行するたびにメッセージが表示されます。
file.00.txt y file.00.txt
file.01.txt y file.01.txt
file.02.txt y file.02.txt
各ファイルについても同様です。はっきりと使っているからこんなことが起きてはいけません。
echo "${array[i]} y ${array[i+1]}" >> placeholder
両方の立場に答えてください。なぜこれが起こるのですか?この問題をどのように解決できますか?
この問題をどのように解決できますか?
ベストアンサー1
コードで奇妙に見える結果が出る理由は、スクリプトが次へ追加出力ファイルに。これは、以前のコード(現在修正済み)にいくつかのバグがあった可能性がありますが、出力ファイルがスクリプトによって削除または空にならないため、出力ファイルでその実行の出力を表示し続けることができます。
スクリプトを次のように短縮できます。
#!/bin/bash
array=( file.*.txt )
for name in "${array[@]}"; do
if [ -n "$prev_name" ] && cmp -s "$prev_name" "$name"
then
printf '%s y %s\n' "$prev_name" "$name"
fi
prev_name=$name
done
これはワイルドカードパターンを使用して、パターンと一致するファイル名で配列を埋めます。
次に、.を使用して配列内の隣のファイル名を比較して名前を繰り返しますcmp -s
。ユーティリティcmp
が終了し、以下が表示されます。本物比較される 2 つのファイルの内容が同じ場合は終了状態です。
$prev_name
このループは、配列の古いファイル名を保存するために使用されます。ループの最初の反復では、この変数は空であるため、ファイルの実際の比較はスキップされます。
あなたは何かもしれない予想される書き込みは二重サイクルです。それはまるで
for nameA in "${array[@]}"; do
for nameB in "${array[@]}"; do
if [ "$nameA" != "$nameB" ] && cmp -s "$nameA" "$nameB"
then
printf '%s y %s\n' "$nameA" "$nameB"
fi
done
done
A
しかし、これも同じです。B
そして B
、A
呼び出しの数は、cmp
関連するファイルの数に応じて2次に増加し、リソースが集中的です(ディスクから読み取るファイルごと配列内のファイル名と同じくらい遅くなります。
同じ内容を含むファイルセットを見つける一般的な方法は次のとおりですfdupes
。
$ fdupes --sameline .
./file.1.txt ./file.2.txt ./file.7.txt
なしで同様の操作を実行するには、fdupes
以下を使用して各ファイルのチェックサムを計算して比較しますmd5sum
。
#!/bin/bash
declare -A names count
while read -r cksum name; do
names[$cksum]+=${names[$cksum]:+,}$name
count[$cksum]=$(( count[$cksum] + 1 ))
done < <( md5sum file.*.txt )
for cksum in "${!count[@]}"; do
if [ "${count[$cksum]}" -gt 1 ]; then
printf '%s\n' "${names[$cksum]}"
fi
done
md5sum
最初のループは、すべての関連ファイルの実行出力を読み取ります。の出力はmd5sum
次のようになります。
897316929176464ebc9ad085f31e7284 file.1.txt
8c9eb686bf3eb5bd83d9373eadf6504b file.10.txt
897316929176464ebc9ad085f31e7284 file.2.txt
26ab0db90d72e28ad0ba1e22ee510510 file.3.txt
84bc3da1b3e33a18e8d5e1bdd7a18d7a file.4.txt
aa6ed9e0f26a6eba784aae8267df1951 file.5.txt
6d7fce9fee471194aa8b5b6e47267f03 file.6.txt
897316929176464ebc9ad085f31e7284 file.7.txt
c30f7472766d25af1dc80b3ffc9a58c7 file.8.txt
9ae0ea9e3c9c6e1b9b6252c8395efdc1 file.9.txt
最初の列のチェックサムをから読みcksum
、ファイル名をから読みますname
。
最初のループでは、チェックサムで索引付けされた連想配列の項目に名前を追加します。ここで、割り当ての実行方法に応じて、必要に応じてnames[$cksum]
各新しい名前の前にカンマを追加します(アイテムにすでに別の名前が含まれている場合)。次に、特定のチェックサムが表示された回数を更新します(2番目のループで使用されます)。
2番目のループでは、チェックサム("${!count[@]}"
連想配列のキー(チェックサム)リストに展開されますcount
)をチェックし、各チェックサムの対応する数が1より大きいかどうかをテストします。これは、重複したファイルが見つかったことを意味します。 3つの同じファイルグループがある場合は、それを-eq 3
代わりに使用できます-gt 1
)。その場合は、そのチェックサムに関連付けられた名前を印刷します。
テストしてみてください:
$ bash script.sh
file.1.txt,file.2.txt,file.7.txt