隣接する大文字と小文字の間にスペースを含めるように、camelCaseファイルの名前を一括変更しようとしています。私はMac OSを使用しているので、私が使用するユーティリティはBSDのバリエーションです。
たとえば、
250 - ErosPhiliaAgape.mp3 => 250 - Eros Philia Agape.mp3
find
次のコマンドを使用して、関連ファイルをサブシェルでmv
実行されているファイルにパイプしようとします。sed
find . -name "*[a-z][A-Z]*" -print0 | xargs -0 -I {} mv {} "$(sed -E 's/([a-z])([A-Z])/\1 \2/g')"
このコマンドだけでも正常に動作します。find
正しいファイルを抽出してsed
名前を正しく変更しましたが、xargsと組み合わせると何も起こりません。
これを行うには何を変更する必要がありますか?
答え1
問題は、コマンドのサブシェルがファイル単位では$(...)
なく、コマンドが実行されたときに評価されることです。 'sをxargs
使用して、a内の各ファイルのコマンド数を計算し、参照を適切に置き換えることができます。find
-exec
sh
find . -name "*[a-z][A-Z]*" -type f -exec sh -c 'echo mv -v "{}" "$(echo "{}" | sed -E "s/([a-z])([A-Z])/\1 \2/g")"' \;
この出力が良好に見える場合は、echo
inを削除してくださいecho mv
。 .echo | sed
\n
答え2
あなたのsed
コマンドはパイプから入力を受けています。と競合するため、xargs
2つのコマンドのそれぞれは、で作成されたデータの一部を取得しfind
(各バイトは1つのリーダーにのみ送信されます)、どのコマンドが何を受け取るかを予測する方法はありません。
各ファイル名をにパイプする必要がありますsed
。つまり、パイプを設定するには中間シェルが必要です。
find . -name "*[a-z][A-Z]*" -print0 | xargs -0 -I {} sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([a-z])([A-Z])/\1 \2/g'\'')"' {}
その必要はありませんxargs
。デフォルトでは役に立たない。find
プログラムを直接呼び出すことができます。
find . -name "*[a-z][A-Z]*" -exec sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([a-z])([A-Z])/\1 \2/g'\'')"' {} \;
または、インストールするrename
次のPerlの実装File::Rename
またはUnicode::Tussle
。
cpan File::Rename
find -depth . -exec rename 's!([a-z])([A-Z])(?!.*/)!$1 $2!g' {} +
この(?!.*/)
ビットは、ディレクトリ名にcamelCaseが含まれている場合にディレクトリ名で置換がトリガーされるのを防ぎます。ディレクトリの名前が変更された場合は、ディレクトリを巡回した後にこれが発生するように渡さ-depth
れます。find
find
答え3
GNU Parallelを使用する場合は、解決策は次のとおりです。
find . -name "*[a-z][A-Z]*" -type f | parallel mv -v {} '{= s:([a-z])([A-Z])(?!.*/):$1 $2:g =}'