多くのテキストエディターでは、検索と置換を行い、見つかった各ケースを検査するオプションが与えられます。 Ubuntuのコマンドラインでこれに似たことができるようになりたいです。 sed
には複数のファイルで文字列を検索して置換する機能がありますが、ユーザーがそれぞれの置換を確認する方法はありますか?
理想的には、ディレクトリ内のすべてのファイルでこの「プロンプト」検索と置換を実行できるソリューションが欲しいです。
Vimはどうですか?
vim '+%s/set/bar/gc' some_file
+
は、ファイルのロード後にコマンドを実行するために使用されます。%
は、バッファー(ファイル)全体に対してコマンドを実行します。gc
は、:substitute
、g
のフラグであり、行内のすべての式に対して作用し、c
は各置換を確認します。実際にVimがファイルを開くのを防ぐことはできませんが、保存と終了を自動化できます。
vim '+bufdo %s/set/bar/gc | up' '+q' some_file another_file
find とその-ok
コマンドの組み合わせを使用できます。このコマンドは-exec
コマンドと同じですが、指定された各コマンドを実行する前にユーザーに最初に尋ねます。ユーザーが同意したら、コマンドを実行します。それ以外の場合は、単にfalseを返します。
from man find
:
-ok command ;
Like -exec but ask the user first. If the user agrees, run the command.
Otherwise just return false. If the command is run, its standard input is
redirected from /dev/null.
したがって、次のようにコマンドを使用できます。
$ find ./ -name filename -ok sed 's/foo/bar/' {} \;
< sed ... filename > ?
これにより、上の2行目に示すようにユーザーにプロンプトが表示されます。
y
と入力すると、sed replacementコマンドが実行され、置換が行われます。 n
と入力すると、-ok
コマンドはsedコマンドを無視します。
ディレクトリ内のすべてのファイルでこの「プロンプト」find
およびreplace
を実行するには、次のようにコマンドを使用します。
$ find /path/to/directory -type f -ok sed 's/foo/bar/' {} \;
ちょっとしたPerlスクリプトを書くだけです。
#!/usr/bin/env Perl
use strict;
use warnings;
my $pat="$ARGV[0]";
my $replacement=$ARGV[1];
my $file="$ARGV[2]";
## Open the input file
open(my $fh, "$file");
## Read the file line by line
while (<$fh>) {
## If this line matches the pattern
if (/$pat/) {
## Print the current line
print STDERR "Line $. : $_";
## Prompt the user for an action
print STDERR "Substitute $pat with $replacement [y,n]?\n";
## Read the user's answer
my $response=<STDIN>;
## Remove trailing newline
chomp($response);
## If the answer is y or Y, make the replacement.
## All other responses will be ignored.
if ($response eq 'Y' || $response eq 'y') {
s/$pat/$replacement/g;
}
}
## Print the current line. Note that this will
## happen irrespective of whether a replacement occured.
print;
}
ファイルを~/bin/replace.pl
として保存し、chmod a+x ~/bin/replace.pl
で実行可能にし、最初の引数として一致するパターン、2番目として置換、3番目としてファイル名で実行します。
replace.pl foo bar file > newfile
すべての*.txt
ファイルなど、複数のファイルで実行するには、bashループでラップします。
for file in *txt; do
replace.pl foo bar "$file" > "$file".new
done
そして、「インプレース」でファイルを編集するには:
for file in *txt; do
tmp=$(mktemp)
replace.pl foo bar "$file" > "$tmp" && mv "$tmp" "$file"
done
vimを使用するmuruの提案 と AFSHINのfind
を使用する提案 (サブディレクトリに再帰するという利点があります)を組み合わせることができます。例:
find ./ -type f -exec vim -c '%s/originalstring/replacementstring/gc' -c 'wq' {} \;