次のような構造のディレクトリがあります。
.
├── Test.txt
├── Test1
│ ├── Test1.txt
│ ├── Test1_copy.txt
│ └── Test1a
│ ├── Test1a.txt
│ └── Test1a_copy.txt
└── Test2
├── Test2.txt
├── Test2_copy.txt
└── Test2a
├── Test2a.txt
└── Test2a_copy.txt
このディレクトリ内のすべてのファイルのmd5チェックサムを作成するbashスクリプトを作成したいと思います。 CLIでスクリプト名を入力し、次にハッシュしたいディレクトリへのパスを入力して、機能させたいと思います。これを達成する方法はたくさんあると確信しています。現在私が持っているもの:
#!/bin/bash
for file in "$1" ; do
md5 >> "${1}__checksums.md5"
done
これはただハングし、機能しません。おそらくfindを使用する必要がありますか?
1つの注意点-ハッシュしたいディレクトリには異なる拡張子のファイルがあり、必ずしもこのまったく同じツリー構造を持つとは限りません。これらのさまざまな状況でも機能するものが必要です。
md5deep
を使用md5deep -r path/to/dir > sums.md5
find
およびmd5sum
の使用find relative/path/to/dir -type f -exec md5sum {} + > sums.md5
md5sum -c sums.md5
を使用してMD5サムのチェックを実行する場合、sums.md5
ファイルを生成したディレクトリと同じディレクトリから実行する必要があることに注意してください。これは、find
が現在の場所に相対的なパスを出力し、sums.md5
ファイルに配置されるためです。
これが問題になる場合は、relative/path/to/dir
を絶対にすることができます(たとえば、$PWD/
をパスの前に置くことで)。これにより、任意の場所からsums.md5
でチェックを実行できます。欠点は、現在sums.md5
に絶対パスが含まれているため、それが大きくなることです。
find
およびmd5sum
を使用するフル機能の関数この関数を.bashrc
ファイル($HOME
ディレクトリにあります)に配置できます。
function md5sums {
if [ "$#" -lt 1 ]; then
echo -e "At least one parameter is expected\n" \
"Usage: md5sums [OPTIONS] dir"
else
local OUTPUT="checksums.md5"
local CHECK=false
local MD5SUM_OPTIONS=""
while [[ $# > 1 ]]; do
local key="$1"
case $key in
-c|--check)
CHECK=true
;;
-o|--output)
OUTPUT=$2
shift
;;
*)
MD5SUM_OPTIONS="$MD5SUM_OPTIONS $1"
;;
esac
shift
done
local DIR=$1
if [ -d "$DIR" ]; then # if $DIR directory exists
cd $DIR # change to $DIR directory
if [ "$CHECK" = true ]; then # if -c or --check option specified
md5sum --check $MD5SUM_OPTIONS $OUTPUT # check MD5 sums in $OUTPUT file
else # else
find . -type f ! -name "$OUTPUT" -exec md5sum $MD5SUM_OPTIONS {} + > $OUTPUT # Calculate MD5 sums for files in current directory and subdirectories excluding $OUTPUT file and save result in $OUTPUT file
fi
cd - > /dev/null # change to previous directory
else
cd $DIR # if $DIR doesn't exists, change to it to generate localized error message
fi
fi
}
source ~/.bashrc
を実行した後、通常のコマンドと同様にmd5sums
を使用できます。
md5sums path/to/dir
このディレクトリとサブディレクトリ内のすべてのファイルのMD5合計を含むchecksums.md5
ディレクトリにpath/to/dir
ファイルを生成します。使用する:
md5sums -c path/to/dir
path/to/dir/checksums.md5
ファイルから合計をチェックします。
path/to/dir
は相対でも絶対でもかまいません。md5sums
はどちらの方法でも正常に動作します。結果のchecksums.md5
ファイルには、常にpath/to/dir
からの相対パスが含まれます。別のファイル名を使用し、checksums.md5
または-o
オプションを指定することにより、デフォルトの--output
を使用できます。 -c
、--check
、-o
、および--output
以外のすべてのオプションは、md5sum
に渡されます。
md5sums
関数定義の前半は、オプションの解析を担当します。詳細については this answer を参照してください。後半には説明コメントが含まれています。
どうですか:
find /path/you/need -type f -exec md5sum {} \; > checksums.md5
pdate#1: @twalbergの推奨に基づいて、ファイル名の空白を処理するコマンドを改善しました。
pdate#2: @jilの提案に基づいて改善され、不要なxargs
呼び出しを削除し、代わりにfindの-exec
オプションを使用します。
pdate#3: @Blakeスクリプトの単純な実装は次のようになります。
#!/bin/bash
# Usage: checksumchecker.sh <path>
find "$1" -type f -exec md5sum {} \; > "$1"__checksums.md5
#!/bin/bash
shopt -s globstar
md5sum "$1"/** > "${1}__checksums.md5"
説明:shopt -s globstar
(manual) は、**
再帰グロブワイルドカードを有効にします。これは、"$1"/**
がパラメーター$1
として指定されたディレクトリの下で再帰的にすべてのファイルのリストに展開されることを意味します。次に、このファイルリストをパラメーターとしてmd5sum
を呼び出すだけで、> "${1}__checksums.md5"
が出力をファイルにリダイレクトします。
md5deep -r $your_directory | awk {'print $1'} | sort | md5sum | awk {'print $1'}
更新された回答
以下の回答または他の回答が気に入った場合は、コマンドを実行する関数を作成できます。そのため、テストするには、ターミナルに次を入力して関数を宣言します。
function sumthem(){ find "$1" -type f -print0 | parallel -0 -X md5 > checksums.md5; }
次に、使用することができます:
sumthem /Users/somebody/somewhere
希望どおりに機能する場合は、その行を "bash profile"の最後に追加すると、関数はいつでも宣言され、使用可能になります。あなたの "bash profile"はおそらく$HOME/.profile
元の回答
すべてのCPUコアを並行して動作させてみませんか?
find . -type f -print0 | parallel -0 -X md5sum
これにより、すべてのファイル(-type f
)現在のディレクトリ(.
)最後にヌルバイトを付けて出力します。次に、これらはGNU Parallelに渡され、ファイル名がヌルバイト(-0
)および一度にできるだけ多くのファイルを実行する必要があること(-X
)ファイルごとに新しいプロセスを作成して保存し、ファイルをmd5sumする必要があります。
このアプローチは、Photoshopファイルのような大きな画像に対して、速度が遅いという点で最大のボーナスを支払います。