2012-01-22 3 views
7

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

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

Вот глупый оболочечной единственный способ, который:

tail_file_to_pattern() { 
    pattern=$1 
    file=$2 

    tail -n$((1 + $(wc -l $file | cut -d' ' -f1) - $(grep -E -n "$pattern" $file | tail -n 1 | cut -d ':' -f1))) $file 
} 

Несколько более надежный способ Perl, который берет файл на стандартный ввод:

perl -we ' 
    push @lines => $_ while <STDIN>; 
    my $pattern = $ARGV[0]; 
    END { 
     my $last_match = 0; 
     for (my $i = @lines; $i--;) { 
      $last_match = $i and last if $lines[$i] =~ /$pattern/; 
     } 
     print @lines[$last_match..$#lines]; 
    } 
' 

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

Легко напечатать все, как в первого появления, например .:

sed -n '/PATTERN/,$p' 

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

+1

Ваше название говорит «все линии вплоть до последний шаблон ", но ваши два примера скриптов печатают все строки от последнего шаблона до конца. Я предполагаю, что это название вводит в заблуждение? –

+0

Если шаблон обычно присутствует и находится ближе к концу, вы можете рассмотреть [File :: ReadBackwards] (http://search.cpan.org/perldoc?File::ReadBackwards) (не переключаясь в буфер до тех пор, пока вы не достигнете шаблон или начало файла). – ikegami

ответ

3

Я предлагаю упростить ваш сценарий оболочки:

tail -n +$(grep -En "$pattern" "$file" | tail -1 | cut -d: -f1) "$file" 

Пришло значительно более кратким, потому что:

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

И он исправляет ошибку, цитируя $ file (поэтому он будет работать с файлами, имена которых содержат пробелы).

4

В качестве альтернативы: tac "$file" | sed -n '/PATTERN/,$p' | tac

EDIT: Если вы не имеете tac эмулировать путем определения

tac() { 
    cat -n | sort -nr | cut -f2 
} 

Гадкий но POSIX.

+0

У меня нет двоичного файла 'tac'. Учитывая, что ОП не указывает операционную систему, вероятно, лучше всего предложить решения, которые будут работать по всем направлениям. – ghoti

+0

Вы можете использовать 'tail -r' вместо' tac'. Хотя это решение не совсем то, о чем спрашивает вопрос. Для этого вам понадобится 'sed -n '1,/$ {pattern}/p" '. –

+1

@ghoti: Ну, похоже, вы не используете GNU/coreutils. По-видимому, 'tac' не POSIX. Если вы настаиваете на POSIX, используйте 'cat -n | sort -nr | cut -f2' вместо 'tac' (О, мы снова уродливы!) –

4

Загрузите данные в массив по строкам и отбросьте массив, когда найдете совпадение с шаблоном. Распечатайте все, что осталось в конце.

while (<>) { 
    @x=() if /$pattern/; 
    push @x, $_; 
} 
print @x; 

В однострочника:

perl -ne '@x=() if /$pattern/;push @x,$_;END{print @x}' input-file 
3

команда СЕПГ q будет делать трюк:

sed "/$pattern/q" $file 

Это будет печатать все строки, пока не дойдет до линии с рисунком , После этого sed напечатает эту последнюю строку и выйдет.

+0

Это делает то, что предлагает название и первая строка вопроса, но не то, что на самом деле интересует вопрос. Он хочет, чтобы все строки * после * включали последнюю строку, которая соответствует заданному шаблону. –

+0

@RobDavis - Ты прав. Я прочитал первый абзац и подумал: «Эй, это просто». Мне, вероятно, придется придумать что-то с Awk. –

6

Вот решение, единственное решение. Для того, чтобы напечатать каждую строку в $fileначиная с последней строкой, которая соответствует $pattern:

sed -e "H;/${pattern}/h" -e '$g;$!d' $file 

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

Вот расстройство того, что он делает, с SED команды в скобках:

  • [H] Append каждую строку в СЕПГ «трюма», но не выводить его на стандартный вывод [D].
  • Когда мы сталкиваемся с рисунком, [h] отбросьте пространство удержания и начните с соответствующей строки.
  • Когда мы дойдем до конца файла, скопируйте пространство удержания в пространство с рисунком [g], чтобы оно было эхо в stdout.

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

+0

+1: Это мощная причудливая обработка. Это одна линия и делает то, что хочет OP. –

1

Это название и описание вопросов не совпадают.

Для получения ответа на вопрос, +1 для ответа @David W. Также:

sed -ne '1,/PATTERN/p' 

Для вопроса в корпусе у вас уже есть некоторые решения.

Отметьте, что tac, вероятно, относится к Linux. Кажется, он не существует в BSD или OSX. Если вы хотите, чтобы решение было многоплатформенным, не полагайтесь на tac.

Конечно, любое решение потребует, чтобы ваши данные были спущены в память или отправлены один раз для анализа и второй раз для обработки. Для Примера:

#!/usr/local/bin/bash 

tmpfile="/tmp/`basename $0`,$$" 
trap "rm $tmpfile" 0 1 2 5 
cat > $tmpfile 

n=`awk '/PATTERN/{n=NR}END{print NR-n+1}' $tmpfile` 

tail -$n $tmpfile 

Обратите внимания, что мое использование tail для FreeBSD. Если вы используете Linux, вам, скорее всего, понадобится tail -n $n $tmpfile.

+0

Вы можете использовать 'tail -r' на OSX, чтобы получить функциональность' tac'. –

+0

Это правда, но он также не является мультиплатформенным, поскольку опция -r' не существует в Linux. Если я рекомендую против одного, мне было бы лицемерно не рекомендовать против другого. :) – ghoti

+0

Я понимаю и согласен полностью - я просто указывал, в основном для любых читателей в будущем, что, если они хотят использовать 'tac' в OS X, они могут вместо этого использовать' tail -r' ... а не оставляя ваше заявление о том, что оно, похоже, не существует. –

1

Роб Дэвис указал мне, что вы сказал вы хотели не то, что вы на самом деле спросили:

Вы сказали:

Я пытаюсь найти сжатые оболочки одного -лайнер, который даст мне все строки в файле до какой-нибудь рисунок.

, но затем в самом конце вашего поста, вы сказали:

Но я не придумал способ печатать все от последнее вхождение.

Я уже дал вам ответ для вашего first question. Вот одна линия ответ на ваш второй вопрос: не Печать из регулярного выражения до конца файла:

awk '{ if ($0 ~ /'"$pattern"'/) { flag = 1 } if (flag == 1) { print $0 } }' $file 

Похожая Perl один вкладыш:

export pattern="<regex>" 
export file="<file>" 
perl -ne '$flag=1 if /$ENV{pattern}/;print if $flag;' $file 
+0

За исключением того, что он хочет, чтобы линии после последнего появления шаблона, я полагаю. –

+0

@RobDavis - Ты прав. Ваше [решение] (http://stackoverflow.com/a/8967705/368630) является лучшим. Это одна линия и независимая от платформы. –

Смежные вопросы