もう一度やり直す気はありませんが、Commandline Find SedExecに答えてこれを書きました。そこで質問者は、おそらくディレクトリを1つか2つ除いて、ツリー全体を移動し、文字列「OLD」を含むすべてのファイルとディレクトリの名前を「NEW」を含むように変更する方法を知りたがっていました。
ほかに記述する方法冗長性を骨の折れると、それはデバッグビルトイン組み込んだで以下を、この方法にも固有のものとすることができます。基本的に、要求された作業を実行するために実行する必要があると思われるすべてのコマンドをコンパイルして変数に保存する以外は、記述されているとおりには何も実行しません。
また、ループを可能な限り明示的に回避します。パターンのsed
複数の一致を再帰的に検索する以外に、私が知る限り、他の再帰はありません。
そして最後に、これは完全にnull
区切られています- null
。以外のファイル名のどの文字にもつまずきません。私はあなたがそれを持つべきではないと思います。
ちなみに、これは本当に速いです。見てください:
% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" | tail -n 2 )
<actual process time used:>
0.06s user 0.03s system 106% cpu 0.090 total
<output from wc:>
Lines Words Bytes
115 362 20691 -
<output from tail:>
mv .config/replacement_word-chrome-beta/Default/.../googlestars \
.config/replacement_word-chrome-beta/Default/.../replacement_wordstars
注:上記のfunction
意志がおそらく必要GNU
のバージョンをsed
し、find
適切に処理するようにfind printf
し、sed -z -e
かつ:;recursive regex test;t
呼び出し。これらが利用できない場合は、いくつかの小さな調整を加えるだけで機能が複製される可能性があります。
これにより、最初から最後まで、ほとんど手間をかけずにすべてを実行できます。私はfork
でやりましたがsed
、sed
再帰的な分岐手法も練習していたので、ここにいます。理髪学校で割引ヘアカットをするようなものだと思います。ワークフローは次のとおりです。
rm -rf ${UNNECESSARY}
- あらゆる種類のデータを削除または破壊する可能性のある機能呼び出しを意図的に省略しました。あなたはそれ
./app
が望ましくないかもしれないと言います。事前に削除するか、別の場所に移動するか、\( -path PATTERN -exec rm -rf \{\} \)
ルーチンfind
を組み込んでプログラムで実行することもできますが、それはすべてあなたのものです。
_mvnfind "${@}"
- 引数を宣言し、worker関数を呼び出します。
${sh_io}
関数からの戻り値を保存するという点で特に重要です。${sed_sep}
すぐに来ます。これはsed
、関数内のの再帰を参照するために使用される任意の文字列です。${sed_sep}
が作用するパス名またはファイル名のいずれかに含まれる可能性のある値に設定されている場合は、そのままにしないでください。
mv -n $1 $2
- ツリー全体が最初から移動されます。それは多くの頭痛を救うでしょう。私を信じてください。あなたがしたい残りのこと-名前の変更-は単にファイルシステムのメタデータの問題です。たとえば、これをあるドライブから別のドライブに移動したり、あらゆる種類のファイルシステムの境界を越えて移動したりする場合は、1つのコマンドで一度に移動することをお勧めします。また、より安全です。;に
-noclobber
設定されたオプションに注意してくださいmv
。書かれているように、この関数はすでに存在する${SRC_DIR}
場所には配置されません${TGT_DIR}
。
read -R SED <<HEREDOC
- sedのすべてのコマンドをここに配置して、煩わしさを回避し、変数に読み込んで、以下のsedにフィードします。以下の説明。
find . -name ${OLD} -printf
find
プロセスを開始します。find
我々はすでにツー場所の全てやったので、名前を変更する必要があります何のためにのみ検索mv
機能の最初のコマンドで操作を。たとえば、呼び出しのfind
ようにで直接アクションを実行するのでexec
はなく、代わりにそれを使用して、で動的にコマンドラインを構築します-printf
。
%dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
- 後
find
突き止め我々はそれが直接構築し、(プリントアウトし必要なファイルほとんどのコマンドのは)私たちはあなたの名前の変更を処理する必要があります。%dir-depth
各行の先頭にタックは、私たちが名前を変更するまだ親オブジェクトとツリー内のファイルやディレクトリの名前を変更しようとしていないことを保証するのに役立ちます。find
あらゆる種類の最適化手法を使用してファイルシステムツリーをウォークしますが、必要なデータが安全な順序で返されるかどうかは定かではありません。これが私たちが次にする理由です...
sort -general-numerical -zero-delimited
- $ {SRC}に最も近いパスが最初に機能
find
する%directory-depth
ように、すべての出力をに基づいて並べ替えます。これにより、mv
ファイルを存在しない場所に移動することで発生する可能性のあるエラーが回避され、再帰的なループの必要性が最小限に抑えられます。(実際、ループを見つけるのは難しいかもしれません)
sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
- これはスクリプト全体で唯一のループで
%Path
あり、置換が必要な可能性のある複数の$ {OLD}値が含まれている場合は、文字列ごとに出力された2番目のループのみをループすると思います。私が想像した他のすべてのソリューションには2番目のsed
プロセスが含まれ、短いループは望ましくないかもしれませんが、プロセス全体の生成とフォークに勝るものは確かです。
- つまり、基本的に
sed
ここで行うことは、$ {sed_sep}を検索し、それを見つけたら、$ {OLD}が見つかるまでそれと遭遇したすべての文字を保存し、それを$ {NEW}に置き換えます。次に、$ {sed_sep}に戻り、文字列内で複数回発生した場合に備えて、$ {OLD}を再度検索します。見つからない場合は、変更された文字列をに出力しstdout
(次に再びキャッチします)、ループを終了します。
- これにより、文字列全体を解析する必要がなくなり、
mv
コマンド文字列の前半(もちろん$ {OLD}を含める必要があります)にそれが含まれ、後半はワイプに必要な回数だけ変更されます。mv
の宛先パスからの$ {OLD}名。
sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
- ここでの2つの
-exec
呼び出しは、秒なしで発生しfork
ます。最初に、これまで見てきたように、$ {OLD}から$ {NEW}へのすべての参照を適切に変更するために、必要に応じて's function commandmv
によって提供されるコマンドを変更しますが、そうするためにいくつかを使用する必要がありました最終出力に含めるべきではない任意の参照点。したがって、必要な作業がすべて終了したら、保持バッファから参照ポイントを消去してから渡すように指示します。 find
-printf
sed
そして今、私たちは戻ってきました
read
次のようなコマンドを受け取ります。
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
これは、意志read
にそれを${msg}
として${sh_io}
機能する意志の外側で検査することができます。
涼しい。
-マイク