Как к grep определенная строка _and_ первая строка файла?

Теперь чрезвычайно легко установить StackApplet на Debian благодаря модулю нейтрализации для AppIndicators, который я записал, который поставлется с StackApplet. Можно установить его путем загрузки исходного пакета для последней версии от ее страницы Launchpad.

Оттуда, просто необходимо извлечь содержание архива и работать:

sudo python setup.py install

... который будет заботиться об установке.

76
09.10.2018, 15:55
16 ответов

Хороший путь

Обычно Вы не можете сделать этого с grep, но можно использовать другие инструменты. AWK был уже упомянут, но можно также использовать sed, как это:

sed -e '1p' -e '/youpattern/!d'

Как это работает:

  1. Утилита Sed работает над каждой строкой индивидуально, выполняя указанные команды на каждом из них. У Вас может быть несколько команд, указывая несколько -e опции. Мы можем предварительно ожидать каждую команду с параметром диапазона, который указывает, должна ли эта команда быть применена к определенной строке или нет.

  2. "1p" первая команда. Это использует p команда, которая обычно печатает все строки. Но мы предварительно ожидаем его с численным значением, которое указывает диапазон, к этому нужно относиться. Здесь, мы используем 1 что означает первую строку. Если Вы хотите распечатать больше строк, можно использовать x,yp где x первая строка должна распечатать, y последняя строка должна распечатать. Например, для печати сначала 3 строк Вы использовали бы 1,3p

  3. Следующая команда d который обычно удаляет все строки из буфера. Перед этой командой мы помещаем yourpattern между два / персонажи. Это - другой путь (сначала должен был указать, какие строки, как мы сделали с p команда) обращения к строкам, в которых должна работать команда. Это означает, что команда будет только работать на строки то соответствие yourpattern. Кроме, мы используем ! символ прежде d команда, которая инвертирует ее логику. Таким образом, теперь это удалит все строки, которые не соответствуют указанному шаблону.

  4. В конце sed распечатает все строки, которые оставляют в буфере. Но мы удалили строки, которые не соответствуют от буфера, поэтому только согласующие отрезки длинной линии будут распечатаны.

Подводя итоги: мы печатаем 1-ю строку, затем мы удаляем все строки, которые не соответствуют нашему шаблону от входа. Отдых строк печатается (поэтому только строки, которые действительно соответствуют шаблону).

Первая проблема строки

Как упомянуто в комментариях, существует проблема с этим подходом. Если указанный шаблон будет соответствовать также первой строке, то он будет распечатан дважды (однажды p команда и однажды из-за соответствия). Мы можем избежать этого двумя способами:

  1. Добавление 1d команда после 1p. Поскольку я уже упомянул, d команда удаляет строки из буфера, и мы указываем, что это - диапазон номером 1, что означает, что это только удалит 1-ю строку. Таким образом, команда была бы sed -e '1p' -e '1d' -e '/youpattern/!d'

  2. Используя 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'

Как это работает

  1. Во-первых, мы используем -n опция добавить номера строки перед каждой строкой. Мы хотим подсчитать все строки мы, мы соответствуем .* - что-либо, даже пустая строка. Как предложено в комментариях, мы можем также соответствовать '^ ', результатом является то же.

  2. Затем мы используем расширенные регулярные выражения, таким образом, мы можем использовать \| специальный символ, который работает ИЛИ. Таким образом, мы соответствуем, если строка запускается с 1: (первая строка), или содержит наш шаблон (в этом случае syslog).

Проблема номеров строки

Теперь проблема, мы получаем это ужасные номера строки в нашем выводе. Если это - проблема, мы можем удалить их с cut, как это:

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-

-d опция указывает разделитель, -f указывает поля (или столбцы), мы хотим распечатать. Таким образом, мы хотим сократить, каждый выравнивает на каждом : символ и печатает только 2-й и все последующие столбцы. Это эффективно удаляет первый столбец с, он - разделитель, и это точно, в чем мы нуждаемся.

67
27.01.2020, 19:31
  • 1
    может быть, покончили cat -n также и выглядел бы более ясным как с grep, злоупотребленным для этого. –  Alfe 12.09.2012, 16:34
  • 2
    nl не считает пустые строки (но печатает их без номера строки), cat -n форматирует нумерацию с предыдущими пробелами, grep -n . полосы пустые строки вообще и добавляют двоеточие. У всех есть их... er... функции ;-) –  Alfe 12.09.2012, 18:19
  • 3
    Очень образовательный правильно написанный ответ. Я пытался заменить, "Притворяются" (Около начала) с, "Предварительно ожидают" для Вас, но требовалось больше изменений, и я не испытывал желание изменять случайное дерьмо в Вашем сообщении, таким образом, Вы могли бы хотеть зафиксировать это. –  Bill K 12.09.2012, 19:57
  • 4
    ps aux | sed '1p;/pattern/!d' распечатает первую строку дважды, если она будет соответствовать шаблону. Лучше всего к используемому b команда: ps aux | sed -e 1b -e '/pattern/!d'. cat -n не POSIX. grep -n '^' пронумеровал бы каждую строку (не, проблема для PS произвела, который не имеет пустых строк). nl -ba -d $'\n' нумерует каждую строку. –  Stéphane Chazelas 13.09.2012, 12:46
  • 5
    Отметьте это 1b;... не является портативным, ни POSIX, не может быть никакой другой команды после "b", таким образом, Вам нужны новая строка или другое-e выражение. –  Stéphane Chazelas 19.09.2012, 00:03

вид, но сохраняет строку заголовка наверху

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

И используйте его как это

$ ps aux | body grep someApp
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp
3
27.01.2020, 19:31
  • 1
    Спасибо, некоторые из тех ответов обсуждают общий случай этого вопроса.Прекрасно! –  dotancohen 13.09.2012, 13:07

Поместите следующее в свой .bashrc файл или скопировать/вставить в оболочку сначала для тестирования.

function psls { 
ps aux|head -1 && ps aux|grep "$1"|grep -v grep;
}

Использование: psls [grep шаблон]

$ psls someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root              21   0.0  0.0  2467312   1116   ??  Ss   Tue07PM   0:00.17 /sbin/someApp

Удостоверьтесь, что получили свой .bashrc (или .bash_profile при помещении его там вместо этого):

source ~/.bashrc

Функция даже автоматически заполнит в командной строке оболочки. Как Вы заявили в другом ответе, можно передать первую строку по каналу в файл для сохранения одного вызова к PS.

4
27.01.2020, 19:31
  • 1
    , я использовал такую функцию в течение многих лет. Я называю свою версию psl, которые только звонят ps и grep однажды каждый (и не нуждается head). –  Adam Katz 14.01.2015, 23:08

Возможно, два ps команды были бы самыми легкими.

$ ps aux | head -1 && ps aux | grep someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
100         3304   0.0  0.2  2466308   6476   ??  Ss    2Sep12   0:01.75 /usr/bin/someApp
4
27.01.2020, 19:31
  • 1
    мне не нравится это решение, прежде всего, потому что ситуация могла измениться между первым и вторым ps aux звонить... И если Вы просто хотите ту статическую первую строку, почему бы не повторить его вручную? –  Shadur 12.09.2012, 14:19
  • 2
    Изменения между двумя вызовами не должны быть побеспокоены в этой ситуации. Первое только предоставит заголовок, который будет всегда соответствовать к выводу второго. –  Alfe 12.09.2012, 16:30
  • 3
    , который я не вижу, почему это было downvoted, он, конечно, является жизнеспособным вариантом. Upvoting. –  dotancohen 12.09.2012, 17:37

Вы могли также использовать tee и head:

ps aux | tee >(head -n1) | grep syslog

Обратите внимание однако что пока tee не может проигнорировать SIGPIPE сигналам (см., например, обсуждение здесь) этот подход нужно обходное решение, чтобы быть надежными. Обходное решение должно проигнорировать сигналы SIGPIPE, это может, например, быть сделано как это в ударе как оболочки:

trap '' PIPE    # ignore SIGPIPE
ps aux | tee >(head -n1) 2> /dev/null | grep syslog
trap - PIPE     # restore SIGPIPE handling

Также обратите внимание, что выходной порядок не гарантируется.

5
27.01.2020, 19:31
  • 1
    я не полагался бы на это для работы, в первый раз, когда я выполнил его (zsh), он произвел заголовки столбцов ниже результатов grep. Во второй раз это было прекрасно. –  Rqomey 12.09.2012, 15:16
  • 2
    я еще не видел это, но один способ увеличить надежность, должен вставить маленькую задержку конвейера перед grep: | { sleep .5; cat }. –  Thor 12.09.2012, 15:42
  • 3
    Добавление снов для предотвращения проблем параллелизма всегда является взломом. Хотя это могло бы работать, это - шаг к темной стороне.-1 для этого. –  Alfe 12.09.2012, 16:36
  • 4
    у меня было несколько других странных проблем при попытке этого ответа, я поставил вопрос для проверки –  Rqomey 12.09.2012, 16:47
  • 5
    Это - интересное использование мишени, но я нахожу это ненадежным, и часто только печатает выходную строку, но не строку заголовка. –  dotancohen 12.09.2012, 17:32

Поддержка ps внутренний фильтр,

Предположим, что Вы ищете процесс удара:

ps -C bash -f

Перечислит весь процесс, который назвал bash.

14
27.01.2020, 19:31
  • 1
    Спасибо, который хорош знать. Однако это не найдет сценарии запущенными с Python среди других. –  dotancohen 12.09.2012, 17:32

Я склонен отправлять заголовок в stderr:

ps | (IFS= read -r HEADER; echo "$HEADER" >&2; cat) | grep ps

Это обычно достаточно в человеческих целях чтения. например:

  PID TTY          TIME CMD
 4738 pts/0    00:00:00 ps

Часть на кронштейнах могла войти в свой собственный сценарий для общего использования.

Существует добавленное удобство, в котором может быть далее передан по каналу вывод (к sort и т.д.), и заголовок останется на вершине.

6
27.01.2020, 19:31
ps aux | { read line;echo "$line";grep someApp;}

Править: после комментариев

ps aux | { head -1;grep someApp;}

Я, хотя head -1 считал бы весь вход, но после тестирования его, он работает также.

{ head -1;grep ok;} <<END
this is a test
this line should be ok
not this one
END

вывод

this is a test
this line should be ok
30
27.01.2020, 19:31
  • 1
    Это - идея, разъясненная непосредственно в ударе. Я хотел бы дать больше чем один ползунок для этого. Я просто, возможно, использовал бы { IFS='' read line; ... } в случае, если заголовок запускается с пробелов. нумерация строк –  Alfe 12.09.2012, 16:31
  • 2
    Это действительно точно принимается за решение проблемы непосредственно.Мило! –  dotancohen 12.09.2012, 17:36
  • 3
    я просто использовал бы head -1 вместо комбинации чтения/эха. –  chepner 12.09.2012, 19:07
  • 4
    Ну, это работает с head -n1 на моем ударе. Это может, вероятно, быть конкретной реализацией. Моя голова не читает целый вход в этом случае, только первая строка, оставляя отдых их во входном буфере. –  Krzysztof Adamski 13.09.2012, 13:11
  • 5
    head -n1 короче, но кажется, что даже спецификация POSIX тиха относительно того, сколько из ее входа позволяется считать, так возможно, read line; echo $line является более портативным, в конце концов. –  chepner 13.09.2012, 14:59

Что Вы думаете об использовании awk вместо grep?

chopper:~> ps aux | awk 'NR == 1 || /syslogd/'
USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root               19   0.0  0.0  2518684   1160   ??  Ss   26Aug12   1:00.22 /usr/sbin/syslogd
mrb               574   0.0  0.0  2432852    696 s006  R+    8:04am   0:00.00 awk NR == 1 || /syslogd/
  • NR == 1: Количество записи == 1; т.е. первая строка
  • ||: или:
  • /syslogd/: Шаблон для поиска

На это могло бы также стоить посмотреть pgrep, хотя это больше для сценариев, а не стоящего с пользователем вывода. Это действительно избегает grep сама команда от появления в выводе, все же.

chopper:~> pgrep -l syslogd
19 syslogd
58
27.01.2020, 19:31
  • 1
    Очень хороший, спасибо. Это также приятно scriptable для будущего расширения. –  dotancohen 12.09.2012, 17:30
  • 2
    , я должен изучить меня некоторый awk.очень мило. –  user606723 13.09.2012, 18:43

Вы могли использовать pidstat с:

pidstat -C someApp
or
pidstat -p <PID>

Пример:

# pidstat -C java
Linux 3.0.26-0.7-default (hostname)    09/12/12        _x86_64_

13:41:21          PID    %usr %system  %guest    %CPU   CPU  Command
13:41:21         3671    0.07    0.02    0.00    0.09     1  java

Дальнейшая информация: http://linux.die.net/man/1/pidstat

4
27.01.2020, 19:31
  • 1
    Спасибо, который хорош знать. Однако это не найдет сценарии запущенными с Python среди других. –  dotancohen 12.09.2012, 17:35

Если это только для процессов Greping с полными заголовками, я бы расширил предложение @ MRB:

$ ps -f -p $(pgrep bash)
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
nasha     2810  2771  0  2014 pts/6    Ss+    0:00 bash
...

PGREP Bash | XARGS PS -FP получит тот же результат, но без подполей. Если требуется другое форматирование:

$ pgrep bash | xargs ps fo uid,pid,stime,cmd -p
  UID   PID STIME CMD
    0  3599  2014 -bash
 1000  3286  2014 /bin/bash
 ...
0
27.01.2020, 19:31

APT-GET знает, что был предоставлен . Он должен устанавливать Apache для выполнения некоторой другой зависимости, возможно PHP5 , который предпочитает libapache2-Mod-phP5 . Попробуйте явно установку PHP5-CGI или PHP5-FPM вместо этого для выполнения PHP5 зависимость.

Если вы не понимаете, почему apt-get вытягивает в какой-то пакет, используйте способность. Это как фронт командной строки с небольшим количеством возможностей, чем APT-Get и текстовый режим полноэкранного интерфейса. Когда пакет вытянут для автоматической установки, Aptitude говорит вам, почему (в полноэкранном интерфейсе видно без ADO: нажмите G После того, как выбираете выбор и выделите пакет, о котором вам интересно, в подтверждении экран).

-121--102796-

Другой способ с GNU ED :

ed -s '!ps aux' <<< $'2,$v/PATTERN/d\n,p\nq\n'

или, если оболочка поддерживает замену процесса:

printf '%s\n' '2,$v/PATTERN/d' ,p q | ed -s <(ps aux)

то есть:

2,$v/PATTERN/d  - remove all lines not matching pattern (ignore the header)
,p              - print the remaining lines
q               - quit

более портативный, без GNU '!' ' или подстановка оболочки - использование только ED R - R EAD Выход PS AUX В буфер, а затем удалите не подходящие линии в диапазоне 2, $ и распечатывают результат:

printf '%s\n' 'r !ps aux' '2,$v/PATTERN/d' ,p q | ed -s

и с момента SED команд в принятых выводах ответа также Линия, соответствующая сами себя, с помощью SED , которая поддерживает -F- и оболочке, которая поддерживает замену процесса, я бы запустил:

printf '%s\n' '2,${' '/PATTERN/!d' '}' | sed -f - <(ps aux)

, что в значительной степени делает то же самое, что и предыдущая Команды ED .

2
27.01.2020, 19:31

Если вы знаете точные номера строк, с Perl это просто! Если вы хотите получить строки 1 и 5 из файла, скажите / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,5]){print}}' < /etc/passwd

Если вы хотите получить и другие строки, просто добавьте их номера в массив.

-2
27.01.2020, 19:31

В основном благодаря Янису Папанагну в comp.unix.shell я использую следующую функцию:

function grep1 {
    IFS= read -r header && printf "%s\n" "$header"; grep "$@"
}

Это имеет ряд преимуществ:

  • Работает с bash, zsh и, возможно, ksh
  • Это прямая замена для grep, поэтому вы можете продолжать использовать любые флаги, которые захотите: -i для сопоставления без учета регистра, -E для расширенных регулярных выражений и т. Д.
  • Всегда дает тот же код выхода, что и grep, на случай, если вы хотите программно определить, действительно ли совпадают какие-либо строки.
  • Ничего не выводит, если вход был пустым

Пример использования:

$ ps -rcA | grep1 databases
  PID TTY           TIME CMD

$ ps -rcA | grep1 -i databases
  PID TTY           TIME CMD
62891 ??         0:00.33 com.apple.WebKit.Databases
3
27.01.2020, 19:31

Способ Perl:

ps aux | perl -ne 'print if /pattern/ || $.==1'

Способ легче читать, чем sed , быстрее, нет риска выбрать нежелательные строки.

1
27.01.2020, 19:31

Сделать регулярное выражение grepумнее:

ps aux | grep -E '%MEM|someApp`

Совпадение заголовка и требуемой информации.

-1
17.11.2021, 23:00

Теги

Похожие вопросы