検索を使用したスクリプトのクリーンアップ - そのファイルやディレクトリはありません。

検索を使用したスクリプトのクリーンアップ - そのファイルやディレクトリはありません。

次のコマンドを使用してサブボリュームセットを見つけて削除します。

find /.snapshots/ -name backup-* -type d -exec btrfs subvolume delete {} \;

うまくいきますが、findで予期しない結果が表示されます。

Delete subvolume (no-commit): '/.snapshots/backup-24-11-2021'    
find: ‘/.snapshots/backup-24-11-2021’: No such file or directory    
Delete subvolume (no-commit): '/.snapshots/backup-25-11-2021'    
find: ‘/.snapshots/backup-25-11-2021’: No such file or directory
    

私はUnixの専門家ではないので、これは少し混乱しています。なぜこれが起こるのですか?

答え1

findが到着したら、/.snapshots/backup-24-11-2021の指示に従ってディレクトリであることを確認してください-type d。ディレクトリなので、指示に従ってくださいfind。完了すると、ディレクトリに到達したばかりで、そのディレクトリに戻ります。結局、ディレクトリへの再帰は.しかし、そのディレクトリはちょうど削除されました。したがって、問題を発見して報告してください。btrfs subvolume delete /.snapshots/backup-24-11-2021-exec …findfindbtrfs subvolume deletefind

find削除したいスナップショットの下で繰り返さないように指示します。これは通常、削除するディレクトリツリー全体を検索するために使用されます。

find /.snapshots/ -name 'backup-*' -type d -exec btrfs subvolume delete {} \; -prune

(注:句の周りに欠落している引用符も修正されました。引用-name符がないとbackup-*実行時に拡張されるため、現在のディレクトリに一致するファイルがある場合、または使用中のシェルにエラーがある場合、コマンドは操作を実行しません。グローバルに一致しませんとfind予想backup-*

しかし、実際にはこれは完全に間違ったコマンドかもしれません。find以下を見てください/.snapshots。たとえば、/.snapshots/saved-for-posterity/usr/src/backup-appコマンドがfindcall で指示するディレクトリがある場合、btrfs subvolume delete /.snapshots/saved-for-posterity/usr/src/backup-appこれは意味がありません。すべてのスナップショットがのサブディレクトリであると仮定し、追加の再帰を防ぐには、次のように渡し/.snapshotsます。-maxdepth 1

find /.snapshots/ -maxdepth 1 -name 'backup-*' -type d -exec btrfs subvolume delete {} \;

唯一の違いは

btrfs subvolume delete /.snapshots/backup-*

現在バックアップがない場合は、btrfs subvolume deleteリテラルパラメータとして呼び出されます。/.snapshots/backup-*

答え2

findディレクトリ内を調べる前にディレクトリを削除したため、エラーメッセージが表示されます。find現在削除されているディレクトリを含むディレクトリ操作が完了すると、egを入力しようとしますが、そのディレクトリが消えたbackup-24-11-2021ため、「ファイルまたはディレクトリが見つかりません」というエラーで失敗します。

ユーティリティがディレクトリに対して深さ優先検索を実行するようにするwithを使用して、-depthこの問題を解決できます。たとえば、検索と削除は、そのfindパスの下の他のすべてのディレクトリを表示した後にのみ発生します。/.snapshots/backup-25-11-2021find

find /.snapshots -depth -name 'backup-*' -type d \
    -exec btrfs subvolume delete {} \;

-nameまた、ファイル名にワイルドカードが含まれているため、テストパラメータを引用する必要があります。

これを行うもう1つの方法は、パスが見つかると検索ツリーからそのパスを削除して、そのパスに深く入ろうとしないようにする-pruneことです。findfind

find /.snapshots -name 'backup-*' -type d -prune \
    -exec btrfs subvolume delete {} \;

3番目のアプローチは、すべてのbackup-*ディレクトリが常に次のすぐ下にある場合です/.snapshotsfind

shopt -s nullglob
for dir in /.snapshots/backup-*; do
    btrfs subvolume delete "$dir"
done

btrfs subvolume delete上記のシェルループは、パターンに一致するすべてのディレクトリを呼び出します/.snapshots/backup-*bashシェルでnullglobシェルオプションを設定すると、シェルは拡張されていないパターンを残さず、一致しないワイルドカードパターンを削除します。

コマンドがbtrfs subvolume delete複数のパス名を引数として使用できる場合は、次のようにする必要があります。

shopt -s failglob
btrfs subvolume delete /.snapshots/backup-*

...指定されたワイルドカードパターンと一致するパス名がない場合、シェルのfailglobシェルオプションはコマンドの実行を防ぎます。bash

関連情報