Назад | Перейти на главную страницу

Удалите одну строку из многих файлов

Я пытаюсь удалить строку из многих текстовых файлов на одном из наших серверов. Строка во всех этих файлах идентична, и я могу запустить:

grep -r -l 'string'  

чтобы получить список файлов, но я застрял в том, как отредактировать файлы и снова записать их в исходные места. Звучит как работа для sed, но не уверен, как обрабатывать вывод.

find -type f -print0 | xargs -0 -n 1 sed -i /string/d сделает свое дело, обрабатывая пробелы в именах файлов и произвольно вложенные frufru, поскольку, по-видимому, люди не могут расширять * самостоятельно.

Вот мой сценарий такого рода, который я называю 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 для соответствия шаблону.

Тьфу. Я вообще не мастер оболочки, но я бы посмотрел на канал для xargs, а затем на sed, чтобы удалить строку с рассматриваемой строкой.

Небольшое прочтение в Google заставляет меня думать, что это может сделать Боба вашим сводным дядей - достаточно близко, чтобы туда добраться.

grep -r -l 'string'  | xargs sed '/string/d' 

Умммммм, это однострочный perl, благодаря прекрасный флаг для локальная фильтрация входных файлов !!

   perl -ni.bak -e 'печатать, если /pattern.to.remove/' файл1 файл2 ...

В контексте...

% 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.)

Затем вы сможете передать это в команду поиска, подобную этой

найти -name -exec grep -v -r -l 'string' {} \;

И это приближается к тому, что вы хотите ... но, конечно, вам нужно будет записать результат обратно в исходный файл ...