このようなコマンド:
find /directory -type f -name "*.txt" -print | xargs rm
ディレクトリとサブディレクトリ内のすべての.txt
ファイルを削除します。これで問題ありません。しかし、ファイル拡張子の変数または配列を作成し、次にfind
を配置すると、たとえば、
TXT=(*.txt)
for ii in ${TXT[@]}; do
find /directory -type f -name $TXT -print | xargs rm
done
このコマンドは、サブディレクトリ内の.txt
ファイルを削除しません。どうして?この2番目のコードを変更してサブディレクトリ内のファイルを削除する方法は?
PS:複数のファイル拡張子があるため、配列を使用しました。
配列の割り当て
TXT=(*.txt)
*.txt
パターンを、そのパターンに一致する現在のディレクトリ内のファイル名のリストに展開します。シェルは、割り当て時にこれを行います。これはあなたが望むものではありません。次のように、find
にリテラル文字列*.txt
を指定します。
pattern='*.txt'
find /directory -type f -name "$pattern" -exec rm {} +
ここでは、xargs rm
も削除しており、代わりにrm
をfind
から直接実行しています。 find
の最新の実装では、-delete
の代わりに非標準の-exec rm {} +
を使用できます。
pattern='*.txt'
find /directory -type f -name "$pattern" -delete
ここでは1つのパターンのみを扱っているため、ここではループは必要ありません。また、find
の呼び出しでの"$pattern"
の引用が重要であることに注意してください。そうしないと、find
が開始する前に、パターンが現在のディレクトリで一致するすべてのファイル名に置き換えられます。
いくつかのパターンでは、次のようなループを実行できます。
patterns=( '*.txt' '*.tmp' )
for pattern in "${patterns[@]}"; do
find /directory -type f -name "$pattern" -delete
done
シェルがパターンをファイル名のグロビングパターンとして使用しないようにするため、配列割り当てでの引用は不可欠です。同じ理由から、"${patterns[@]}"
と"$pattern"
の引用も同様に重要です。
別のアプローチは、複数のパターンがある場合でも、find
を1回だけ呼び出すことです。 /directory
が大規模なディレクトリ階層である場合、これはかなり高速になります。次のコードは、使用するfind
の-name
テストの配列を作成することにより、これを実行します。
patterns=( '*.txt' '*.tmp' )
name_tests=( )
for pattern in "${patterns[@]}"; do
name_tests+=( -o -name "$pattern" )
done
# "${name_tests[@]:1}" removes the initial "-o", which shouldn't be there.
name_tests=( '(' "${name_tests[@]:1}" ')' )
find /directory -type f "${name_tests[@]}" -delete
上記のスクリプトでは、最後に実行される実際のコマンドは次のようになります。
find /directory -type f '(' -name '*.txt' -o -name '*.tmp' ')' -delete
...ファイル名のサフィックス.txt
or.tmp
を含むすべての通常のファイルを、ディレクトリ/directory
内またはその下に削除します。