私はetckeeperのgitレプリカを持っており、etckeeper
名前はusrkeeper
。./foo-etckeeper-bar
./foo-usrkeeper-bar
関連ファイルを見つけるのは簡単です。
% find . -path '*etckeeper*' -print
しかし、実際に名前を変更する方法がわかりません。私は次のものxargs
と組み合わせようとしましたmv
。
% find . -path '*etckeeper*' -print0 | xargs -0 -n 1 -J % bash -c mv % '$(echo' % \| sed \"s/etckeeper/usrkeeper/\" \)
読みやすくするためにエスケープされていない後半は、次のように表示されますxargs -0 -n 1 -J % bash -c mv % $(echo % | sed "s/etckeeper/usrkeeper/" )
。これに関するアイデアは、置き換えのために$()
ファイル名をパイプすることですsed
。
ここでの問題は、bash -c
実行に必要なコマンドが単一の文字列であることです。その後、パラメータを位置パラメータとして解釈し始めます。私はすべての内容を引用することができます:
% find . -path '*etckeeper*' -print0 | xargs -0 -n 1 -J % bash -c 'mv % $(echo % | sed "s/etckeeper/usrkeeper/g" )'
しかし、今はxargs
交換されません%
。この問題をどのように解決できますか? (また、参照として、etckeeper
名前を含むファイルが name を含むディレクトリに存在する場合、ディレクトリがファイルの前に移動されるetckeeper
ため、上記の操作は失敗します。)
ベストアンサー1
名前変更コマンドを使用できます(参照:編集1)。
ソリューション1
合理的な数のファイル/ディレクトリの場合は、bash 4オプションを設定してグローバルスター(再帰名には適用されません。編集3):
shopt -s globstar
rename -n 's/etckeeper/userkeeper/g' **
ソリューション2
ファイル/ディレクトリの数が多い場合は、名前変更と検索を2つの手順で使用して、名前を変更したばかりのディレクトリでファイルの名前変更が失敗するのを防ぎます(参照)。編集2):
find . -type f -exec rename 's/etckeeper/userkeeper/g' {} \;
find . -type d -exec rename 's/etckeeper/userkeeper/g' {} \;
編集1:
2つの名前変更コマンドがあります。。この答えは、Debianベースのディストリビューションで利用可能なPerlベースの名前変更コマンドを使用します。 Debian ベースではなくディストリビューションにインストールするには、次のものが必要です。cpanからインストール可能またはキャッチ。
編集2:
-depth
Jeff Schallerがコメントでfindオプションを指摘したように、オプションProcess each directory's contents before the directory itself
ごとに「ソートされた」ルックアップで-depth
十分です。
find . -depth -exec rename 's/etckeeper/userkeeper/g' {} \;
編集3
etckeeper/etckeeper/etckeeper
解決策1は、外部レベルが内部レベルよりも前に処理され、内部レベルへのポインタが役に立たなくなるため、再帰的な名前変更ターゲット(たとえば)には機能しません。 (最初の名前の後にetckeeper/etckeeper/etckeeper
名前が付けられるため、usrkeeper/etckeeper/etckeeper
名前をetckeeper/etckeeper/
およびに置き換えるとetckeeper/etckeeper/etckeeper
失敗します)。オプションはfind
同じ問題を解決します-depth
。
編集4
Casがコメントで指摘したように、{}\;代わりに {}+ を使用します。 - Perlスクリプトをフォークすると(たとえば、ファイル/ディレクトリごとに1回)、費用がかかります。