
"$d"ディレクトリには、.txt拡張子を持つ何千もの電子メールファイルが含まれています。電子メールクライアントで開くには、名前を.emlに変更する必要があります。
このコマンドは名前を正しく変更しますか?
find "${d}" -type f -name '*.txt' | while read f; do mv -vn "${f}" "${f%.*}".eml; done
それともこれを行うより良いより強力な方法がありますか?
私はエレガントな使い方を考えることはできません。
-exec ...{}... \;
答え1
あなたの解決策は通常大丈夫ですが、改行のために中断されます。以下は少し強力なbash4+ソリューションです。
shopt -s globstar nullglob
for file in **/*.txt; do
mv "$file" "${file%.*}.eml"
done
答え2
私の考えでは、あなたは大丈夫だと思います。
find "$d" -name \*.txt -exec rename .txt .eml {} \;
でも
for f in *.txt; do rename .txt .eml "$f"; done
すべてのファイルが同じディレクトリにある場合。
答え3
bash
はい、同様の構文のシェルを使用すると仮定すると、コマンドは機能します。将来的には、このような大規模なコマンドの使用を検討する際に、echo
コマンドラインを使用して結果をプレビューできることに注意してください。つまり、前に置いてecho
パイプmv
ラインを実行して、コマンドが何であるかを確認できます。よかったら、削除しecho
て実際にコマンドを実行してください。
答え4
zshではzmv
これを簡単にしてください。autoload -U zmv
yours を入力し~/.zshrc
た後、いくつかの方法のいずれかを使用して、**/*.txt
現在のディレクトリとサブディレクトリの拡張子を持つファイルと一致する代替テキストを指定します。txt
zmv '**/*.txt' '$f:r.eml'
zmv '**/*.txt' '${f%.*}.eml'
zmv '(**/)(*).txt' '$1$2.eml'
zmv -w '**/*.txt' '$1$2.eml'
zshはありませんが、bash ≥4またはksh93がある場合は、**
再帰を使用してサブディレクトリを巡回してから一致を繰り返すことができます。 bash(あなたのものに入れてください)またはksh(あなたのものに入れてください)を使って**
最初にglobモードを有効にする必要があります。これはzshでも機能します(プリセットは必要ありません)。shopt -s globstar
~/.bashrc
set -o globstar
~/.kshrc
for f in **/*.txt; do mv -- "$f" "${f%.*}.eml"; done
これにより、通常のファイルだけでなくすべてのファイルの名前が変更されます。ディレクトリやその他の非正規ファイルがあり、それを変更せずに保持したい場合:
zmv -Q '**/*.txt(.)' '$f:r.eml'
for f in **/*.txt; do [[ -f $f ]] && mv -- "$f" "${f%.*}.eml"; done
POSIXの外部にはシェル機能がないため、find
サブディレクトリを参照するには呼び出す必要があります。バックスラッシュ、末尾の空白、または改行を含むファイルでは、ソリューションが破損するため脆弱です。次のコマンドを使用して、末尾のスペースとバックスラッシュの問題を解決できます。while IFS= read -r f; do …
しかし、パイプで接続された出力はfind
本質的に改行で中断されます。代わりに使用してください-exec
。 Linuxではこのユーティリティを使用できますrename
(ディストリビューションに付属しているものは何でも)。 Debian、Ubuntu、およびその派生物:
rename 's/\.txt$/.eml/' **/*.txt
find . -name '*.txt' -type f -exec rename 's/\.txt$/.eml/' {} +
.txt
他のディストリビューションでは、中間にファイル名がない限り(rename
ソース文字列の最初のエントリが置き換えられるため):
rename .txt .eml **/*.txt
find . -name '*.txt' -type f -exec rename .txt .eml {} +
プロセス全体でPOSIX機能のみが使用され、名前変換を実行するためにシェルを呼び出します。
find . -name '*.txt' -type f -exec sh -c 'for f; do mv "$f" "${f%.*}.eml"; done' _ {} +
find
をサポートするには、バージョンが古すぎる場合は、-exec … +
各ファイルに対してシェルを呼び出す必要があります。これにより、コードが簡単になりますが、遅くなります。
find . -name '*.txt' -type f -exec sh -c 'mv "$0" "${0%.*}.eml"; done' {} \;