方法はあるかfindコマンドのみファイル名の先頭に文字列を追加するには?
つまり、次のようになります。
201a.txt
201b.png
...
こうなります:
foo_201a.txt
foo_201b.png
...
これ:
find . -name '201*' -execdir mv {} foo_{} \;
部分にはファイル名の{}
先頭が含まれており、 に書き込もうとするため、機能しません。./
foo_./201*
find だけではこれが不可能な場合、ファイル名の先頭に文字列を追加する最も移植性の高い (つまり、coreutils のみで、シェル スクリプトがなく、最も理解しやすい) 方法は何ですか?
答え1
いいえ。しかし、rename
コマンドは簡単な解決策を提供します。
$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$
答え2
いかがでしょうか
find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}
basename
は によって提供されcoreutils
、xargs
は によって提供されるためfindutils
、少なくともそれfind -execdir
自体と同じくらい移植性があるはずです。
あるいは、POSIXシェルの機能のみを使用する
find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;
答え3
これは、 だけでは不可能でありfind
、GNU find でも不可能です。GNU find は、-printf foo_%p
の代わりにを使用することで、コマンドラインプレフィックスを削除し、代わりに別のプレフィックスを付けてファイルを印刷できます-print
が、 には同様のものはありません-exec
。
(find -printf 'mv foo_%p …' | sh
危険を冒してでも を使うことができます。これは「おとなしい」ファイル名でのみ機能し、ファイル名にスペース、引用符、その他の特殊文字が含まれているとひどく壊れます。したがって、これは行わないでください。)
これを行う標準的な方法 (どの POSIX システムでも機能し、一般的な方法でもある) は、シェルを呼び出して文字列操作を行うことです。
find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;
-execdir
これは GNU 拡張機能であり、移植性を要求されたため、使用しません。 は{}
引数としてシェルに渡されることに注意してください。{}
シェル コード内では絶対に使用しないでください。移植性がないだけでなく、最も重要なのは、ファイル名がシェル コードとして解釈され、ファイル名に特殊文字が含まれている場合に失敗するためです。
最新の POSIX システム (過去 10 年間のもの) では、シェル呼び出しをバッチ処理することでこのコマンドを少し高速化できます。
find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +
あるいは、ksh、bash、または zsh では、 を呼び出す代わりに再帰的なグロブを使用できますfind
。
set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
mv -- "$x" "${x%/*}/foo_${x##*/}"
done
答え4
代わりにアスタリスク ( *
)を使用して./
部分を削除することもできます。
find * -name '201*' -exec mv {} foo_{} \;