回答:
vimを使用しないのはなぜですか?
vimですべてのファイルを開く
vim $(find . -type f)
または、関連するファイルのみを開く(Calebの提案どおり)
vim $(grep 'from' . -Rl)
そして、すべてのバッファで置換を実行します
:bufdo %s/from/to/gc | update
でもできますsed
が、私のsedの知識は限られています。
grep
ず、代わりにを使用find
して既知の一致があるファイルのみを開くことで、これを高速化できます。vim $(grep 'from' . -Rl)
-l -pe
引数(-i
)として渡されたファイルに対して行ごとに置換()を実行するように指示されている小さなPerlスクリプトを使用して、大雑把なことができます。
perl -i -l -pe '
if (/from/) { # is the source text present on this line?
printf STDERR ("%s: %s [y/N]? ", $ARGV, $_); # display a prompt
$r=<STDIN>; # read user response
if ($r =~ /^[Yy]/) { # if user entered Y:
s/from/to/g; # replace all occurences on this line
}' /path/to/files
可能な改善点は、プロンプトの一部に色を付け、「現在のファイル内のすべての出現箇所を置き換える」などのサポートを提供することです。行に出現するたびに個別にプロンプトを出すのは困難です。
2番目の部分は、ファイルのマッチングです。関連するファイルが多すぎず、zshを実行している場合は、現在のディレクトリとそのサブディレクトリ内のすべてのファイルを再帰的に照合できます。
perl -i -l -pe '…' **/*(.)
シェルがbash≥4の場合、を実行できますがperl … **/*
、sedはディレクトリでの実行を試行(および失敗)するため、誤ったエラーメッセージが生成されます。Cファイルなどの一連のファイルで置換のみを実行する場合は、一致を制限できます(これは、bash≥4またはzshで機能します)。
perl -i -l -pe '…' **/*.[hc]
置き換えるファイルを細かく制御する必要がある場合、またはシェルに再帰的なディレクトリマッチングコンストラクト**
がない場合、またはファイルが多すぎて「コマンドラインが長すぎる」エラーが発生する場合は、を使用してくださいfind
。たとえば、名前が付けられたすべてのファイル、*.h
または*.c
現在のディレクトリとそのサブディレクトリで置換を実行するには(古いシステム\;
で+
は、行末ではなくを使用する必要があります(+
フォームは高速ですが、どこでも使用できるわけではありません)。
find . -type f -name '*.[hc]' -exec perl -i -l -pe '…' {} +
とはいえ、対話が必要な場合は、対話型エディターを使用します。GertはVimでこれを行う方法を示しましたが、検索するすべてのファイルを開く必要があるため、たくさんある場合は問題になる可能性があります。
Emacsでは、これを行う方法は次のとおりです。
M-x find-name-dired
(トップレベルディレクトリをM-x find-dired
指定)または(任意のfind
コマンドラインを指定)を使用してファイル名を収集します。t
てすべてのファイルをマークし、次にQ
(dired-do-query-replace-regexp
)を押してマークされたファイルを要求する置換を実行します。sdiff
(http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiffを参照してください)ここで重宝するかもしれません。これを使用すると、インタラクティブなパッチを適用できます。したがって、置換操作を実行して作成した一時ファイルを使用してそれを行うことはsed
、可能な解決策になる可能性があります。
# use file descriptor 3 to still allow use of stdin
while IFS= read -r -d '' file <&3; do
# write the result of the replacement into a temporary file
sed -r 's/something/something_else/g' -- "$file" > replacer_tmp
if cmp -s -- "$file" replacer_tmp; then
continue; # nothing was replaced
fi
echo "There is something to replace in '$file'! Starting interactive diff."
echo
sdiff -o "$file" -s -d -- "$file" replacer_tmp
echo
done 3< <(find . -type f -print0)
(非POSIXプロセス置換を使用しread -d
、サポートされてbash
いるファイルループなど)
s/from/to/g
するのではなく、フォーマットの不具合のように読みます(Markdownでそれを行うことはできません。およびHTMLタグ)。s/from/to/gc
c
<code>
<strong>