Поиск и замена с терминала, но с подтверждением
Во многих текстовых редакторах вы можете выполнять поиск и замену, и вам предоставляется возможность проверить каждый найденный случай. Я хотел бы иметь возможность сделать что-то подобное в командной строке в Ubuntu. я знаю sed
предлагает возможность находить и заменять строки в нескольких файлах, но есть ли способ подтвердить каждую замену пользователем?
В идеале я хотел бы получить решение, которое позволило бы мне выполнять поиск и замену по запросу для всех файлов в каталоге.
4 ответа
Как насчет Вима?
vim '+%s/set/bar/gc' some_file
+
используется для запуска команды после загрузки файла.%
запускает команду по всему буферу (файлу).gc
флаги для:substitute
,g
для действия над всеми выражениями в строке иc
для подтверждения каждой замены.
На самом деле вы не можете запретить Vim открывать файл, но вы можете автоматизировать сохранение и выход:
vim '+bufdo %s/set/bar/gc | up' '+q' some_file another_file
bufdo
запускает команду над каждым буфером Это включает в себя часть после|
, поэтому изменения в каждом буфере сохраняются (up
).q
выходит, который выходит из Vim, так как мы находимся в последнем буфере.
Вы можете использовать комбинацию поиска и его -ok
команда. Эта команда такая же, как -exec
команда, но сначала спросите пользователя перед выполнением каждой указанной команды. Если пользователь согласен, запустите команду. В противном случае просто верните false.
от 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 > ?
это подскажет пользователю, как показано во второй строке выше.
Если вы введете y
тогда будет выполнена команда замены sed, и будет произведена ваша замена. Если вы введете 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
и запустите его с шаблоном для совпадения в качестве первого аргумента, заменой в качестве второго и именем файла в качестве третьего:
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 с предложением AFSHIN использоватьfind
(который имеет преимущество повторения в подкаталогах), например:
find ./ -type f -exec vim -c '%s/originalstring/replacementstring/gc' -c 'wq' {} \;