У меня есть длинный файл журнала, где каждая запись начинается со строки, содержащей только дефисы.
8 ответов
Вы можете сделать это с помощью сценария оболочки таким образом:
#!/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}'
Однако имейте в виду, что он работает, накапливая строки в строку и удаляя строку всякий раз, когда находит строку дефиса. Затем, в конце, он просто выводит строку (все строки после последней строки дефиса).
На первый взгляд, это может показаться более эффективным, но на самом деле это не так. В (по общему признанию, не исчерпывающем) тестах в моей системе, это на самом деле работало немного медленнее, я думаю, что это связано со многими происходящими добавлениями строк. Дело в том, что решение сценария кажется более быстрым, несмотря на то, что оно делает несколько проходов данных (возможно, потому что каждый проход очень ограничен в том, что он делает).
awk -vRS="-+" 'END{print}' ORS="" file
Вы также можете сделать это с помощью 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
%
(с некоторыми отступами эти точки с запятой должны быть новыми строками).
Я думаю, что это легко сделать с помощью sed
. Вы хотите, чтобы команда , чтобы найти конечную (т.е. последний) линии только-дефис, и вы хотите , чтобы p
RINT от этой точки до конца файла.
К сожалению, я не очень хорош с седом. Надеясь, кто-то еще может уточнить.
РЕДАКТИРОВАТЬ
ОК, sed
не идеален. Вот как это сделать с помощью ex
, текстового двойника vi
:
ex filename
$
?----------
.,$p
q
tac file | grep -B 10000 -m 1 -- '------' | tac
Вероятно, это не самое эффективное решение:
#!/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"
Используйте tac
и sed
:
$ cat log-file --- first ------ second --- last $ tac log-file | sed -e '/^-\+$/,$d' | tac last
echo "`sed -n '/^--*$/=' <file> | tail -1`,\$p" <file> | xargs sed -n
Но мне больше нравится решение Нормана Грея. Может еще больше понравится, если он это объяснит :-)