У меня есть длинный файл журнала, где каждая запись начинается со строки, содержащей только дефисы.

8 ответов8

3

Вы можете сделать это с помощью сценария оболочки таким образом:

#!/bin/bash
if [[ -z "$1" ]] ; then
    echo Usage: $0 '<inputFile>'
    exit 1
fi
line=$(grep -n '^--*$' "$1" | tail -1 | sed 's/:.*//')
if [[ -z "${line}" ]] ; then
    cat "$1"
else
    sed "1,${line}d" "$1"
fi

Учитывая входной файл:

this is line 1
-------
this is line 3
-------
this is line 5
this is line 6

он производит:

this is line 5
this is line 6

Для пояснения grep -n создает ряд строк, таких как:

2:-------
4:-------

где 2 и 4 - номера строк. Затем tail -1 просто отфильтровывает все, кроме последнего, а sed удаляет все, начиная с двоеточия и заканчивая концом строки, оставляя только номер строки.

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


Кроме того, мой оригинальный ответ включал этот фрагмент awk который будет обрабатывать файл только один раз:

awk '/^--*$/{s=""}{s=s$0"\n";}END{print s}'

Однако имейте в виду, что он работает, накапливая строки в строку и удаляя строку всякий раз, когда находит строку дефиса. Затем, в конце, он просто выводит строку (все строки после последней строки дефиса).

На первый взгляд, это может показаться более эффективным, но на самом деле это не так. В (по общему признанию, не исчерпывающем) тестах в моей системе, это на самом деле работало немного медленнее, я думаю, что это связано со многими происходящими добавлениями строк. Дело в том, что решение сценария кажется более быстрым, несмотря на то, что оно делает несколько проходов данных (возможно, потому что каждый проход очень ограничен в том, что он делает).

3
awk -vRS="-+" 'END{print}' ORS="" file
2

Вы также можете сделать это с помощью sed:

% cat t.txt
this is line 1
this is line 2
-------
this is line 3
----
this is line 4
-------
this is line 5
this is line 6
% sed -n -e '/^---*/{h;d;}' -e H -e '${g;p;}' t.txt
-------
this is line 5
this is line 6
% 

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

1

Я думаю, что это легко сделать с помощью sed . Вы хотите, чтобы команда , чтобы найти конечную (т.е. последний) линии только-дефис, и вы хотите , чтобы p RINT от этой точки до конца файла.

К сожалению, я не очень хорош с седом. Надеясь, кто-то еще может уточнить.


РЕДАКТИРОВАТЬ

ОК, sed не идеален. Вот как это сделать с помощью ex , текстового двойника vi:

ex filename
$
?----------
.,$p
q
1
tac file | grep -B 10000 -m 1 -- '------' | tac
0

Вероятно, это не самое эффективное решение:

#!/bin/bash

file=$1
pattern='^-+$'
declare -i count=0
declare -i index=0

while read -r line
do
    count+=1
    [[ $line =~ $pattern ]] && index=$count
done < "$file"

tail -n "$((count - index))" "$file"
0

Используйте tac и sed:

$ cat log-file 
---
first
------
second
---
last

$ tac log-file | sed -e '/^-\+$/,$d' | tac
last
0
echo "`sed -n '/^--*$/=' <file> | tail -1`,\$p" <file>  | xargs sed -n

Но мне больше нравится решение Нормана Грея. Может еще больше понравится, если он это объяснит :-)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .