sed: возврат последнего совпадения вхождения до конца файла

используя sed, как вернуть последнее совпадение до конца файла? (FYI это было упрощено)

до сих пор я пробовал:

sed -n '/ Statistics |/,$p' logfile.log

который возвращает все строки с первого матча (почти весь файл)

Я тоже пробовал:

$linenum=`tail -400 logfile.log | grep -n " Statistics |" | tail -1 | cut -d: -f1`
sed "$linenum,$!d" logfile.log

это работает, но не будет работать над ssh-соединением в одной команде, действительно нужно, чтобы все это было в одном конвейере.

формат файла журнала: следует:

(есть заголовки статистики с данными sub, записанными в файл журнала каждую минуту, цель этой команды-вернуть самый последний заголовок статистики вместе с любыми связанными ошибками, которые возникают после заголовка)

Statistics |
   Stuff
   More Stuff
   Even more Stuff
Statistics |
   Stuff
   More Stuff
Error: incorrect value
Statistics |
   Stuff
   More Stuff
   Even more Stuff
Statistics |
   Stuff
Error: error type one
Error: error type two

EOF

возврат должен быть:

Statistics |
   Stuff
Error: error type one
Error: error type two

6 ответов


Если у вас tac в наличии:

tac INPUTFILE | sed '/^Statistics |/q' | tac

ваш пример скрипта имеет пробел перед статистикой, но ваши примеры данных, похоже, нет. Это имеет регулярное выражение, которое предполагает, что статистика находится в начале строки; настроить, если это неверно.

sed -n '/^Statistics |/h;/^Statistics |/!H;$!b;x;p'

когда вы видите статистику, замените пространство удержания текущей строкой (h). В противном случае добавьте в пространство удержания (H). Если мы не находимся в конце файла, остановитесь здесь (b). В конце файла распечатайте пространство удержания (x извлечь содержимое трюм; p печать).

на sed script, команды необязательно имеют префикс "address". Чаще всего это регулярное выражение, но оно также может быть номером строки. Адрес /^Statistics |/ выбирает все строки, соответствующие регулярному выражению; /^Statistics |/! выбирает строки, не соответствующие регулярному выражению; и $! соответствует всем строкам, кроме последней строки в файле. Команды без явного адреса выполняются для всех входных строк.

редактировать объяснить напишите более подробно и добавьте следующее.

обратите внимание, что если вам нужно передать это на удаленный хост, используя ssh, вам понадобятся дополнительные уровни цитирования. Одним из возможных обходных путей, если он становится слишком сложным, является сохранение этого сценария на удаленном хосте и просто ssh remotehost path/to/script. Другим возможным обходным путем является изменение выражений адресации, чтобы они не содержали восклицательных знаков (это проблематично в командной строке, например, в Бить.)

sed -n '/^Statistics |/{h;b};H;${x;p}'

это тоже несколько проще!

третьим возможным обходным путем, если stdin вашего SSH-конвейера не привязан к другим вещам,является передача скрипта с вашего локального хоста.

echo '/^Statistics |/h;/^Statistics |/!H;$!b;x;p' |
ssh remotehost sed -n -f - file

Это может сработать для вас:

sed '/Statistics/h;//!H;$!d;x' file
Statistics |
   Stuff
Error: error type one
Error: error type two

Если вы довольны awk решение, это своего рода работает (помимо получения дополнительной пустой строки):

awk '/^Statistics/ { buf = "" } { buf = buf "\n"  } END { print buf }' input.txt

sed ':a;N;$!ba;s/.*Statistics/Statistics/g' INPUTFILE

должен работать (GNU sed 4.2.1).

Он читает весь файл в одну строку, затем заменяет все, от начала до последнего Statistics (слова в комплекте) с Statistics, и печатает то, что осталось.

HTH


Это также может работать, немного более простая версия решения sed, данного другими выше:

sed -n 'H; /^Statistics |/h; ${g;p;}' logfile.log

выход:

Statistics |
   Stuff
Error: error type one
Error: error type two