Хороший способ
Обычно вы не можете сделать это с помощью 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и т.д. в популярности: это важно для части , чтобы подвести итог в единое целое.