좋은 생각

좋은 생각

간단한 grep 예를 가정해 보겠습니다.

$ psa aux | grep someApp
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

이는 많은 정보를 제공하지만 ps 명령의 첫 번째 줄이 누락되었으므로 해당 정보에 대한 컨텍스트가 없습니다. ps의 첫 번째 줄도 표시하고 싶습니다.

$ psa aux | someMagic 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

물론, 특히 ps에 대해 grep에 정규식을 추가할 수 있습니다.

$ ps aux | grep -E "COMMAND|someApp"

그러나 첫 번째 행도 갖고 싶은 다른 상황이 있기 때문에 더 일반적인 솔루션을 선호합니다.

좋은 활용 사례가 될 것 같습니다"stdmeta" 파일 설명자.

답변1

좋은 생각

일반적으로 grep으로는 이 작업을 수행할 수 없지만 다른 도구를 사용할 수 있습니다. AWK는 이미 언급되었지만 sed다음과 같이 사용할 수도 있습니다.

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

작동 방식:

  1. Sed 유틸리티는 각 라인에서 개별적으로 작동하여 각 라인에서 지정된 명령을 실행합니다. 여러 옵션을 지정하여 여러 명령을 사용할 수 있습니다 -e. 각 명령 앞에 범위 매개변수를 추가하여 명령이 특정 행에 적용되는지 여부를 지정할 수 있습니다.

  2. "1p"가 첫 번째 명령입니다. p일반적인 명령을 사용하여 모든 줄을 인쇄합니다. 하지만 적용할 범위를 지정하기 위해 앞에 숫자를 추가합니다. 여기서는 1첫 번째 줄을 의미하는 which를 사용합니다. 더 많은 줄을 인쇄하려면 인쇄할 첫 번째 줄 과 인쇄할 마지막 줄 x,yp을 사용할 수 있습니다 . 예를 들어 처음 3줄을 인쇄하려면 사용할 수 있습니다.xy1,3p

  3. 다음 명령은 d일반적으로 버퍼의 모든 라인을 삭제합니다. 이 명령 앞에는 yourpattern/문자 사이에 배치합니다. 이는 명령이 실행되어야 하는 라인을 지정하는 또 다른 방법입니다 p(먼저 명령에서 했던 것처럼 어떤 라인을 지정하는지). 이는 명령이 일치하는 행에서만 작동함을 의미합니다 yourpattern. 이 외에도 명령 앞에 !문자를 사용하여 d논리를 뒤집습니다. 이제 모든 행이 삭제됩니다.원하지 않는다지정된 패턴과 일치합니다.

  4. 마지막으로 sed는 버퍼에 남아 있는 모든 행을 인쇄합니다. 그러나 일치하지 않는 줄을 버퍼에서 제거하므로 일치하는 줄만 인쇄됩니다.

요약하면 첫 번째 줄을 인쇄한 다음 패턴과 일치하지 않는 입력에서 모든 줄을 제거합니다. 나머지 줄이 인쇄됩니다. 따라서 해당 줄만 인쇄됩니다.하다일치하는 패턴).

첫 번째 줄 질문

댓글에서 언급했듯이 이 접근 방식에는 문제가 있습니다. 지정된 패턴이 첫 번째 줄에도 일치하면 두 번 인쇄됩니다( p명령으로 한 번, 일치로 인해 한 번). 다음 두 가지 방법으로 이를 방지할 수 있습니다.

  1. 뒤에 1d명령을 추가합니다 1p. 이미 언급했듯이 d이 명령은 버퍼에서 줄을 삭제하고 범위를 숫자 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. \|그런 다음 OR 역할을 하는 특수 문자를 사용할 수 있도록 확장 정규식을 사용합니다 . 따라서 줄이 1:(첫 번째 줄)로 시작하거나 패턴을 포함하는 경우(이 경우 syslog) 일치합니다.

줄번호 문제

이제 문제는 출력에 이 보기 흉한 줄 번호가 나온다는 것입니다. 이것이 문제라면 다음을 사용하여 제거할 수 있습니다 cut.

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

-d옵션은 구분 기호를 지정하여 -f인쇄하려는 필드(또는 열)를 지정합니다. 따라서 우리는 모든 문자의 모든 줄을 잘라내고 :두 번째 열과 모든 후속 열만 인쇄하려고 합니다. 이렇게 하면 첫 번째 열과 해당 구분 기호가 효과적으로 제거되는데, 이것이 바로 우리에게 필요한 것입니다.

답변2

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

답변3

ps aux | { IFS= read -r line; printf '%s\n' "$line";grep someApp;}

head내장 head( ksh93활성화 사용) 과 같은 일부 구현의 경우 , builtin head모든 빌드 ksh93에 포함되지는 않습니다.

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

그러나 대부분의 head구현에서는 입력을 검색할 수 없는 경우(예: 파이프) 청크로 입력을 읽을 때는 작동하지 않습니다.

그리고:

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

대부분의 구현에서는 head다음만 얻을 수 있습니다.

this is a test
this line should be ok

여기서는 파이프 대신 임시 파일을 사용하여 문서를 구현하는 셸을 사용하세요.

이 명령은 한 줄 이상의 입력을 읽지 않도록 보장하기 때문에 line사용 가능한 곳에서 작동합니다(이전에는 표준 명령이었지만 기능에 대한 액세스로 인해 표준에서 제거됨 ).IFS= read -r

의 경우 ( cho의 경우 dit의 경우와 혼동하지 마세요 )를 zsh사용할 수도 있습니다 . 또한 NUL 바이트를 차단하지 않는 유일한 쉘이기도 합니다.IFS= read -re-eebash-eeread

답변4

나는 헤더를 보내는 경향이 있습니다표준 에러:

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

일반적으로 사람이 읽는 목적에는 이 정도면 충분합니다. 예를 들어:

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

대괄호 안의 섹션은 일반적인 사용을 위해 자체 스크립트에 넣을 수 있습니다.

sort또한 출력을 추가로 파이프할 수 있고 헤더가 맨 위에 유지된다는 추가적인 편의성도 있습니다 .

관련 정보