ファイルのコピー/チェックサム用のスクリプトを作成しています... CentOS、Debian、またはOpenBSDに移植できる可能性のある最新のMac OS X/FreeBSDを実行しています
スクリプトの詳細:
もちろん、ファイルの整合性チェックはHW/HDDレベルで行われ、S.M.A.R.T.)で簡単にチェックできるため、偏執的ですが、10年後、元の整合性をチェックできません。チェックサムはで作成されますCF/XDカードはオリジナルです...好きなだけコピーでき、いわゆる腐ったビットやハードウェアエラーなどを心配する必要はありません。
もちろん、rsyncも使用できますが、衝突の可能性がある廃止されたMD5/SHA1チェックサムのアイデアは好きではありません。適切な場所に適切なタイミングで配置し、1枚のユニークな写真を撮るには何時間もの作業、「運」、そして汗が必要です...元のRAWを失った場合...それは永遠に失われ、記憶だけが残ります。
「パラノイドだけが生き残る」-AndyGroove
ステップ1の簡単な作業スクリプトがあります。スクリプト内:
today=`date +%Y-%m-%d`
CHK='shasum -a512'
CHK_OUTPUT=($today)-checksum.txt
find . -type f ! -name ".*" -maxdepth 1 -exec $CHK {} \; > "$CHK_OUTPUT"
期待どおりにチェックサムファイルを取得しましたが、質問は「改善できますか?」です。
...cf83e1357eef47417a81a538327af927da3e ./(2017-07-19)-checksum.txt
煩わしい./を取り除きたいので、次のようにコーディングしました...
find ./ -type f ! -name ".*" -maxdepth 1 -exec bash -c '$CHK $(basename {}) > $CHK_OUTPUT' \;
残念ながら、次のエラーが発生します
bash: ${CHK_OUTPUT}: ambiguous redirect
別の試み
find ./ -type f ! -name ".*" -maxdepth 1 -exec bash -c '$CHK $(basename {})' \; > $CHK_OUTPUT
それはどういうわけか動作しますが、奇妙な結果になります
私はUTFMで失敗しました&RTFMそして私はGoogleに尋ねる方法さえわかりません:-D
誰かがそれを行う方法を提案できますか?
よろしく
デビッド
-exec
のサブシェルに引数を渡す方法find
の-exec
を使用すると、正しく識別したとおり、サブシェルを使用して複雑なコマンドを渡すことができます。ただし、アプローチにはいくつかの問題があります。
外部変数$CHK
は一重引用符で囲まれているため、展開されません。サブシェルにこの変数を知らせるためにできることは、前にexport
することです。
$ foo=bar
$ find . -type f -exec sh -c 'echo "$foo"' \;
(returns an empty line for every file found)
$ export foo=bar
$ find . -type f -exec sh -c 'echo "$foo"' \;
(returns "bar" for every file found)
変数をエクスポートすると、サブシェルが読み取ることができる環境の一部になります。または、それをサブシェルへの個別の引数として渡します。これは、ここでの頼りになる方法です。
$ foo=bar
$ find . -type f -exec sh -c 'echo "$0"' "$foo" \;
(returns "bar" for every file found)
もちろん、$1
、$2
などを続けて、サブシェルの引数として{}
を使用して、実際のファイル名を使用することもできます。そして、変数を引用することを忘れないでください。
実際には、コマンドを次のように簡単に書き直すことができます。
shasum -a512 * > "$CHK_OUTPUT"
shasum
は、ループやfind
なしで、複数のファイルを読み取る1つのコマンドでジョブを実行するのに十分賢いためです。デフォルトでは、*
にはドットで始まるファイルが含まれていません(ただし、shopt -s dotglob
で変更できます)。したがって、特にfind
が1の場合、maxdepth
オプションは不要です。
しかし、shasum
がそれほど賢くなかったとしましょう。それで、さらにいくつかのオプションを提供できます。 find
を使用する場合、これは複数の引数を処理する方法です。
CHK='shasum -a512'
find ./ -type f ! -name ".*" -maxdepth 1 -exec \
sh -c '$0 "$(basename "$1")"' "$CHK" {} \; > "$CHK_OUTPUT"
しかし、それでも、これはすべて、より読みやすいものとして書き直すこともできます。
today=$(date +%Y-%m-%d)
for f in *; do shasum -a512 "$f" > "($today)-checksum.txt"; done
多くの場合、find
を使用するよりもファイルをループする方が簡単ですが、*
の拡張により、その方法で処理できるファイルの数には制限があります。ある時点で、コマンドラインには長すぎます(具体的な制限は、OSとシェルによって異なります)。
もちろん、Bash≥4.0のshopt -s globstar
を使用して再帰的に実行することもできます。
shopt -s globstar
for f in **/*; do …; done
しかし、これも次と同じです。
shasum -a512 **/* > "$CHK_OUTPUT"
[〜#〜]更新[〜#〜]
残念ながら、以下で説明するコマンドは、ファイルがないサブディレクトリに空のchecksum.txtを作成します。
find ./ -type f \( ! -iname ".*" ! -iname "\(????-??-??\)-checksum.txt" \) -maxdepth 1 -exec sh -c '$0 "$(basename "$1")"' "$CHK" {} \; > $CHK_OUTPUT
理由はわかりませんが、応急修理があります
# remove empty checksum.txt
if [[ -f $CHK_OUTPUT ]] && [[ ! -s $CHK_OUTPUT ]]; then
rm $CHK_OUTPUT
fi
================================================= ===
最終的な解決策...これまでのところうまくいくようです**
find ./ -type f \( ! -iname ".*" ! -iname "\(????-??-??\)-checksum.txt" \) -maxdepth 1 -exec sh -c '$0 "$(basename "$1")"' "$CHK" {} \; > $CHK_OUTPUT