2

シェルコードについて助けが必要です。今、私はこのコードを持っています:

find $dirname -type f -exec md5sum '{}' ';' | sort | uniq --all-repeated=separate -w 33 | cut -c 35-

このコードは、指定されたディレクトリで (同じ内容の) 重複ファイルを見つけます。私がする必要があるのは、それを更新することです-最新の(日付ごとに)変更されたファイルを(重複ファイルリストから)見つけ、そのファイル名を出力し、ターミナルでそのファイルを削除する機会を与えます。

4

2 に答える 2

0

純粋な bash でこれを行うのは少し厄介です。これを perl や python で書く方がはるかに簡単です。

また、これを bash ワンライナーで実行しようとしている場合は、実現可能かもしれませんが、方法がわかりません。

とにかく、以下の純粋なbashソリューションが本当に必要な場合は、あなたが説明したことをしようとする試みです.

その点に注意してください:

  • 私は実際に rm を呼び出しているのではなく、単にエコーしているだけです - ファイルを破壊したくありません
  • そこには、私が完全に満足していない「read -u 1」があります。

コードは次のとおりです。

#!/bin/bash

buffer=''

function process {
    if test -n "$buffer"
    then
        nbFiles=$(printf "%s" "$buffer" | wc -l)
        echo "================================================================================="
        echo "The following $nbFiles files are byte identical and sorted from oldest to newest:"
        ls -lt -c -r $buffer
        lastFile=$(ls -lt -c -r $buffer | tail -1)
        echo

        while true
        do
            read -u 1 -p "Do you wish to delete the last file $lastFile (y/n/q)? " answer
            case $answer in
                [Yy]* ) echo rm $lastFile; break;;
                [Nn]* ) echo skipping; break;;
                [Qq]* ) exit;;
                * ) echo "please answer yes, no or quit";;
            esac
        done
        echo
    fi
}

find . -type f -exec md5sum '{}' ';' |
sort                                 |
uniq --all-repeated=separate -w 33   |
cut -c 35-                           |
while read -r line
do
    if test -z "$line"
    then
        process
        buffer=''
    else
        buffer=$(printf "%s\n%s" "$buffer" "$line")
    fi
done
process

echo "done"
于 2013-10-30T23:16:22.887 に答える
0

で実装された「単純な」ソリューションです (2 つの外部コマンドを除いて:md5sumもちろん、statユーザーの快適さのためにのみ使用され、アルゴリズムの一部ではありません)。このことは、100% Bash のクイックソートを実装しています (私はそれを誇りに思っています)。

#!/bin/bash

# Finds similar (based on md5sum) files (recursively) in given
# directory. If several files with same md5sum are found, sort
# them by modified (most recent first) and prompt user for deletion
# of the oldest

die() {
   printf >&2 '%s\n' "$@"
   exit 1
}

quicksort_files_by_mod_date() {
    if ((!$#)); then
        qs_ret=()
        return
    fi
    # the return array is qs_ret
    local first=$1
    shift
    local newers=()
    local olders=()
    qs_ret=()
    for i in "$@"; do
        if [[ $i -nt $first ]]; then
            newers+=( "$i" )
        else
            olders+=( "$i" )
        fi
    done
    quicksort_files_by_mod_date "${newers[@]}"
    newers=( "${qs_ret[@]}" )
    quicksort_files_by_mod_date "${olders[@]}"
    olders=( "${qs_ret[@]}" )
    qs_ret=( "${newers[@]}" "$first" "${olders[@]}" )
}

[[ -n $1 ]] || die "Must give an argument"
[[ -d $1 ]] || die "Argument must be a directory"

dirname=$1

shopt -s nullglob
shopt -s globstar

declare -A files
declare -A hashes

for file in "$dirname"/**; do
    [[ -f $file ]] || continue
    read md5sum _ < <(md5sum -- "$file")
    files[$file]=$md5sum
    ((hashes[$md5sum]+=1))
done

has_found=0
for hash in "${!hashes[@]}"; do
    ((hashes[$hash]>1)) || continue
    files_with_same_md5sum=()
    for file in "${!files[@]}"; do
        [[ ${files[$file]} = $hash ]] || continue
        files_with_same_md5sum+=( "$file" )
    done
    has_found=1
    echo "Found ${hashes[$hash]} files with md5sum=$hash, sorted by modified (most recent first):"
    # sort them by modified date (using quicksort :p)
    quicksort_files_by_mod_date "${files_with_same_md5sum[@]}"
    for file in "${qs_ret[@]}"; do
      printf "   %s %s\n" "$(stat --printf '%y' -- "$file")" "$file"
    done
    read -p "Do you want to remove the oldest? [yn] " answer
    if [[ ${answer,,} = y ]]; then
       echo rm -fv -- "${qs_ret[@]:1}"
    fi
done

if((!has_found)); then
    echo "Didn't find any similar files in directory \`$dirname'. Yay."
fi

スクリプトは自明だと思います(ストーリーのように読むことができます)。これは私が知っているベスト プラクティスを使用しており、ファイル名に不適切な文字 (スペース、改行、ハイフンで始まるファイル名、改行で終わるファイル名など) が含まれていても 100% 安全です。

これは bash のグロブを使用するため、肥大化したディレクトリ ツリーがある場合は少し遅くなる可能性があります。

いくつかのエラー チェックがありますが、多くは欠落しているため、本番環境ではそのまま使用しないでください。(これらを追加するのは簡単ですが、かなり面倒です)。

アルゴリズムは次のとおりです。指定されたディレクトリ ツリー内の各ファイルをスキャンします。ファイルごとに、その md5sum を計算し、連想配列に格納します。

  • filesキーはファイル名、値は md5sums です。
  • hashesキーを使用すると、ハッシュと値がファイルの数になり、その md5sum がキーになります。

これが完了したら、見つかったすべての md5sum をスキャンし、複数のファイルに対応するものだけを選択してから、この md5sum を持つすべてのファイルを選択し、変更日でそれらをクイックソートして、ユーザーにプロンプ​​トを表示します。

重複が見つからない場合の効果: スクリプトはユーザーに適切に通知します。

これが最も効率的な方法だとは言えませんが (たとえば、Perl の方が優れているかもしれません)、とても楽しく、驚くほど読みやすく、従うことができ、勉強することで多くのことを学べる可能性があります!

bash バージョン ≥ 4 にのみあるいくつかのバシズムと機能を使用します。

お役に立てれば!

述べる。システムdateにスイッチがある場合は、コマンドを次-rのように置き換えることができます。stat

date -r "$file"

述べる。echoの前を離れましたrm。スクリプトの動作に問題がなければ削除してください。次に、3 つの外部コマンドを使用するスクリプトが作成されます:)

于 2013-10-31T09:48:13.673 に答える