Убрать одну строку из множества файлов
Я пытаюсь удалить строку из многих текстовых файлов на одном из наших серверов. Строка одинакова для всех этих файлов, и я могу запустить:
grep -r -l 'string'
чтобы получить список файлов, но я застрял на том, как получить файлы, отредактированные и записанные в их исходных местах снова. Звучит как работа для sed, но не уверен, как справиться с выводом.
5 ответов
Вот мой сценарий для такого рода вещей, который я называю remove_line
:
#!/usr/bin/perl
use IO::Handle;
my $pat = shift(@ARGV) or
die("Usage: $0 pattern files\n");
$pat = qr/$pat/;
die("Usage $0 pattern files\n")
unless @ARGV;
foreach my $file (@ARGV) {
my $io = new IO::Handle;
open($io, $file) or
die("Cannot read $file: $!\n");
my @file = <$io>;
close($io);
foreach my $line (@file) {
if($line =~ /$pat/) {
$line = '';
$found = 1;
last;
}
}
if($found) {
open($io, ">$file") or
die("Cannot write $file: $!\n");
print $io @file;
close($io);
}
}
Так вы делаете remove_line 'string'
файлы в вашем списке.
Преимущества делать это по сравнению с использованием sed
Вы не должны беспокоиться о платформо-зависимом поведении sed -i
и вы можете использовать регулярное выражение Perl для соответствующего шаблона.
find -type f -print0 | xargs -0 -n 1 sed -i /string/d
сделает свое дело, обрабатывая пробелы в именах файлов и произвольно вложенных фруктах, так как очевидно, что люди не способны расширяться *
самостоятельно.
Тьфу. Я вовсе не волшебник оболочки, но я бы посмотрел на канал для xargs, а затем на sed, чтобы удалить строку с рассматриваемой строкой.
Little bit of Google perusal makes me think that this might make Bob your stepuncle - close enough to get there anyway.
grep -r -l 'string' | xargs sed '/string/d'
Хмммммм, это perl one-liner, благодаря прекрасному флагу -i для фильтрации входных файлов на месте!!
perl -ni.bak -e 'печатать, если /pattern.to.remove/' file1 file2 ...
В контексте...
% echo -e 'foo\ngoo\nboo' >test
% perl -ni.bak -e 'print unless /goo/' test
% diff test*
--- test 2010-01-06 05:09:13.503334739 -0800
+++ test.bak 2010-01-06 05:08:28.313583066 -0800
@@ -1,2 +1,3 @@
foo
+goo
boo
Вот краткий справочник об использованном заклинании Perl...
% perl --help
Usage: perl [switches] [--] [programfile] [arguments]
-e program one line of program (several -e's allowed, omit programfile)
-i[extension] edit <> files in place (makes backup if extension supplied)
-n assume "while (<>) { ... }" loop around program
и для дополнительного кредита, вы можете использовать touch -r file.bak file
скопировать старую метку времени в новый файл. однако, иноды будут отличаться, и странные вещи могут произойти, если у вас есть жесткие ссылки в миксе... проверьте документы, если вы заинтересованы в том, чтобы скрыть свои треки... Хмммм, что вы снова использовали?
Не забывайте о опции -v в grep, которая меняет смысл
grep -v -r -l 'string'
Справочная страница Frok fom grep:
-v, --invert-match
Invert the sense of matching, to select non-matching lines. (-v is specified by POSIX.)
Затем вы можете передать это в команду поиска, подобную этой
find -name -exec grep -v -r -l 'string'
{} \;
И это приближается к тому, что вы хотите... но, конечно, вам нужно записать результат обратно в исходный файл...