スクリプトは配列の正しい要素を正しく印刷しません。

スクリプトは配列の正しい要素を正しく印刷しません。

したがって、デフォルトでは、作業ディレクトリ(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 そして BA呼び出しの数は、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

おすすめ記事