Хороший способ
Обычно вы не можете сделать это с помощью grep, но вы можете использовать другие инструменты. AWK уже упоминался, но вы также можете использовать sed
, как это:
sed -e '1p' -e '/youpattern/!d'
Как это устроено:
Утилита Sed работает в каждой строке индивидуально, выполняя указанные команды для каждой из них. Вы можете иметь несколько команд, указав несколько -e
параметров. Мы можем добавить к каждой команде параметр диапазона, который указывает, должна ли эта команда применяться к определенной строке или нет.
«1p» - это первая команда. Он использует p
команду, которая обычно печатает все строки. Но мы добавляем к нему числовое значение, которое указывает диапазон, к которому он должен применяться. Здесь мы используем, 1
что означает первую строку. Если вы хотите напечатать больше строк, вы можете использовать x,yp
где x
первая строка для печати, y
последняя строка для печати. Например, чтобы напечатать первые 3 строки, вы должны использовать1,3p
Следующая команда, d
которая обычно удаляет все строки из буфера. Перед этой командой мы ставим yourpattern
между двумя /
символами. Это другой способ (сначала было указать, какие строки, как мы делали с p
командой) адресации строк, на которых должна выполняться команда. Это означает, что команда будет работать только для совпадающих строк yourpattern
. Кроме того, мы используем !
символ перед d
командой, которая инвертирует его логику. Так что теперь он удалит все строки, которые не соответствуют указанному шаблону.
В конце sed напечатает все строки, которые остались в буфере. Но мы удалили строки, которые не совпадают из буфера, поэтому будут напечатаны только совпадающие строки.
Подводя итог: мы печатаем 1-ю строку, затем удаляем из строки все строки, которые не соответствуют нашему шаблону. Остальные строки печатаются (так только те строки , которые делают соответствовать шаблону).
Проблема с первой линией
Как уже упоминалось в комментариях, существует проблема с этим подходом. Если указанный шаблон соответствует также первой строке, он будет напечатан дважды (один раз по p
команде и один раз из-за совпадения). Мы можем избежать этого двумя способами:
Добавление 1d
команды после 1p
. Как я уже упоминал, d
команда удаляет строки из буфера, и мы указываем его диапазон номером 1, что означает, что он будет удалять только 1-ю строку. Таким образом, команда будетsed -e '1p' -e '1d' -e '/youpattern/!d'
Используя 1b
команду вместо 1p
. Это трюк. b
Команда позволяет нам перейти к другой команде, указанной меткой (таким образом, некоторые команды могут быть опущены). Но если эта метка не указана (как в нашем примере), она просто переходит к концу команд, игнорируя остальные команды для нашей строки. Так что в нашем случае последняя d
команда не удалит эту строку из буфера.
Полный пример:
ps aux | sed -e '1b' -e '/syslog/!d'
Используя точку с запятой
Некоторые sed
реализации могут сэкономить вам ввод текста, используя точку с запятой для разделения команд вместо использования нескольких -e
параметров. Так что если вы не заботитесь о переносимости, команда будет ps aux | sed '1b;/syslog/!d'
. Он работает по крайней мере в GNU sed
и busybox
реализации.
Сумасшедший путь
Вот, однако, довольно сумасшедший способ сделать это с помощью grep. Это определенно не оптимально, я публикую это только для целей обучения, но вы можете использовать его, например, если у вас нет другого инструмента в вашей системе:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
Как это устроено
Сначала мы используем -n
опцию, чтобы добавить номера строк перед каждой строкой. Мы хотим пронумеровать все строки, которые нам соответствуют, .*
что угодно, даже пустую строку. Как предлагается в комментариях, мы также можем сопоставить '^', результат тот же.
Затем мы используем расширенные регулярные выражения, чтобы мы могли использовать \|
специальный символ, который работает как OR. Таким образом, мы сопоставляем, если строка начинается с 1:
(первая строка) или содержит наш шаблон (в данном случае его syslog
).
Проблема с номерами строк
Теперь проблема в том, что мы получаем эти ужасные номера строк в нашем выводе. Если это проблема, мы можем удалить их cut
следующим образом:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-d
Параметр указывает разделитель, -f
указывает поля (или столбцы), которые мы хотим напечатать. Поэтому мы хотим разрезать каждую строку на каждом :
символе и печатать только 2-й и все последующие столбцы. Это эффективно удаляет первый столбец с его разделителем, и это именно то, что нам нужно.
ack
так полезны, и почемуperl
взлетела в прошломsed
,awk
и т.д. в популярности: это важно для части , чтобы подвести итог в единое целое.