Я пытаюсь передать что-то, что вернет только первый "абзац" или "раздел", разделенный пустой строкой. Я думал, что могу использовать awk
или, sed
чтобы получить диапазон, как в некоторых других ответах, но это, похоже, не работает.
$ cat txt
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
$ cat txt |awk '/^Package:/,/^$/'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
Разве он не должен возвращать только первый «раздел»? (согласно: Grep, начиная с фиксированного текста, до первой пустой строки и https://www.unix.com/shell-programming-and-scripting/148692-awk-script-match-pattern-till-blank-line.html)
- Если я использую
grep -ve ^$
его, пустые строки удаляются, поэтому нет никаких специальных символов. Если я попытаюсь извлечь другую часть, я получу части из обоих «разделов»:
$ cat txt |awk '/^Package:/,/^Version:/' Package: plasma-desktop Architecture: amd64 Version: 4:5.12.9.1-0ubuntu0.1 Package: plasma-desktop Architecture: amd64 Version: 4:5.12.4-0ubuntu1
Если я использую
sed -n '/^Package:/,/^$/p'
или ,sed -n '/^Package:/,/^Version:/p'
я получаю те же результаты, что и эквивалент awk.
Как мне получить awk
или sed
прекратить после первого случая?
решение1
Именно поэтому в awk есть режим абзаца:
$ awk -v RS= 'NR==1' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
и для печати 2-й записи достаточно просто очевидно изменить NR==1
на NR==2
:
$ awk -v RS= 'NR==2' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y
Кстати, никогда не используйте выражения диапазонов - они делают код для тривиальных проблем немного короче, чем при использовании флага, но затем, если ваши требования изменятся хоть немного, потребуется полностью переписать или дублировать условия. Так что в любое время, когда вы думаете, что вам может понадобиться использовать /begin/,/end/
sed или awk, используйте /begin/{f=1} f{print} /end/{f=0}
вместо этого awk, и это даст вам НАМНОГО больше контроля над тем, когда/как печатать начальные/конечные строки и т. д.
решение2
В /begin/,/end/
"флаги действий" включаются каждый раз, когда /begin/
находится совпадение, и выключаются, когда /end/
совпадение находится. Также печатаются линии границ с "begin" и "end".
Последствия вашего ввода таковы (в приведенных ниже примерах после напечатанных строк дается комментарий):
- С
'/^Package:/,/^$/'
:
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.9.1-0ubuntu0.1 #
Supported: 3y #
#TURN OFF
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.4-0ubuntu1 #
Supported: 3y #
- С
'/^Package:/,/^Version:/'
:
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.9.1-0ubuntu0.1 #TURN OFF
Supported: 3y
Package: plasma-desktop #TURN ON
Architecture: amd64 #
Version: 4:5.12.4-0ubuntu1 #TURN OFF
Supported: 3y
Чтобы напечатать только абзац, начинающийся с «Пакет:», вы можете написать
sed -ne '/^$/q' -e '/^Package:/,$p' file
sed
прекращает обработку файла, как только находит пустую строку из-за /^$/q
.
С awk
:
awk '/^$/{exit};/^Package:/,0' file
решение3
Как прокомментировалКвазимодо
/begin/,/end/
получает строки, которые соответствуют этим регулярным выражениям, включая граничные строки. begin включает печать, а end выключает. Строка сразу после вашей пустой строки снова включает печать, потому чтоPackage:
в ней также есть.
Я понял, что могу использовать sed
и изменить /begin/
to 0
, и он начнется с начала. Поскольку начало только одно, оно совпадет только один раз.
$ cat txt |sed -n '0,/^$/p'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y