티를 사용하여 grep으로 리디렉션하는 방법


13

티를 사용한 경험이 많지 않기 때문에 이것이 기본적이지 않기를 바랍니다.

이 질문에 대한 답변 중 하나를 본 후 나는 이상한 행동을 보았습니다 tee.

첫 번째 줄과 찾은 줄을 출력하려면 다음을 사용할 수 있습니다.

ps aux | tee >(head -n1) | grep syslog
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4

그러나 처음 (zsh에서)이 결과를 잘못된 순서로 실행하면 열 머리글이 grep 결과 아래에 있었지만 (다시 발생하지는 않았지만) 명령을 바꾸려고했습니다.

ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

첫 줄만 인쇄되고 다른 것은 없습니다! 티를 사용하여 grep으로 리디렉션 할 수 있습니까, 아니면 잘못된 방법으로 수행합니까?

이 질문을 입력 할 때 두 번째 명령이 실제로 한 번 작동했으며 5 번 다시 실행 한 다음 한 줄 결과로 돌아갔습니다. 이게 내 시스템인가요? (tmux 내에서 zsh를 실행 중입니다).

마지막으로, 첫 번째 명령으로 "grep syslog"가 결과로 표시되지 않는 이유는 무엇입니까 (결과는 하나만 있음)?

제어를 위해 여기없는 grep이 있습니다. tee

ps aux | grep syslog
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4
henry    2290  0.0  0.1  95220  3092 ?        Ssl  Sep07   3:12 /usr/bin/pulseaudio --start --log-target=syslog
henry   15924  0.0  0.0   3128   824 pts/4    S+   13:44   0:00 grep syslog

업데이트 : head가 전체 명령을 자르고있는 것 같습니다 (아래 답변에 표시된 것처럼) 아래 명령은 이제 다음을 반환합니다.

ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
syslog     806

귀하의 질문에 대한 직접적인 대답은 아니지만 다음과 같은 일을하는 것이 훨씬 깨끗합니다 ps aux | sed -n -e '1p' -e '/syslog/p'.
jw013

나는 sed를 생각조차하지 않았다. 나는 그것이 관련 질문에 대한 적절한 대답 일지 모른다고 생각 하지만 실제로는 이러한 명령의 일관되지 않은 행동에 대한 정보를 찾고있다!
Rqomey

답변:


19
$ ps aux | tee >(head -n1) | grep syslog
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND 
syslog     806  0.0  0.0  34600   824 ?        Sl   Sep07   0:00 rsyslogd -c4

grephead데이터를 사용할 수있게되면, 일반적으로 명령은 거의 동시에 시작하고, 모두가 자신의 여가 시간 같은 입력 데이터를받을 수 있지만. 라인을 뒤집는 '동기화되지 않은'출력을 도입 할 수있는 것들이 있습니다. 예를 들면 다음과 같습니다.

  1. 의 멀티플렉싱 된 데이터는 tee주로의 구현에 따라 다른 프로세스보다 먼저 한 프로세스로 전송됩니다 tee. 간단한 tee구현은 read어느 정도의 입력을 한 다음 write두 번 수행합니다. 한 번 stdout하고 한 번은 인수에. 즉, 해당 목적지 중 하나가 먼저 데이터를 가져옵니다.

    그러나 파이프는 모두 버퍼링됩니다. 이러한 버퍼는 각각 한 줄이지 만, 더 클 수 있으므로 grep다른 명령 ( head)이 데이터를 수신 하기 전에 수신 명령 중 하나가 출력 (예 : ped 행)에 필요한 모든 것을 볼 수 있습니다. 모두.

  2. 위의 내용에도 불구하고 이러한 명령 중 하나가 데이터를 수신하지만 제 시간에 아무 작업도 수행 할 수없는 경우 다른 명령이 더 많은 데이터를 수신하여 신속하게 처리 할 수 ​​있습니다.

    예를 들어, 경우에도 head하고 grep있는 경우, 한 번에 하나의 라인으로 데이터를 전송 head그것을 처리하는 (또는 커널 스케줄링 지연 도착) 방법을 알고하지 않습니다, grep전에 결과를 표시 할 수 있습니다 head, 심지어는 할 수있는 기회를 가져옵니다. 설명하기 위해 지연을 추가해보십시오 . ps aux | tee >(sleep 1; head -n1) | grep syslog출력을 거의 확실하게 grep먼저 출력합니다 .

$ ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

head첫 번째 입력 줄을 수신 한 다음 stdin을 닫고 종료 하기 때문에 종종 한 줄만 얻는다고 생각합니다 . 시 tee의 표준 출력이 폐쇄 된 것을보고, 그 다음에 자신의 표준 입력 (출력 종료 ps)하고 종료합니다. 구현에 따라 다를 수 있습니다.

효과적으로 데이터 만 ps(때문에 확실히, 전송에 도달 첫 번째 행은 head이를 제어), 그리고 어쩌면 다른 라인 이전 headtee자신의 표준 입력 디스크립터를 닫습니다.

두 번째 줄이 나타나는지 여부와의 불일치는 타이밍에 의해 발생합니다. headstdin을 닫지 만 ps여전히 데이터를 보내고 있습니다. 이 두 이벤트는 잘 동기화되지 않았으므로 포함하는 행에 syslog여전히 tee인수 ( grep명령) 가 될 가능성이 있습니다. 위의 설명과 비슷합니다.

stdin / exiting을 닫기 전에 모든 입력을 기다리는 명령을 사용하면이 문제를 완전히 피할 수 있습니다. 예를 들어, awk대신에 head모든 행을 읽고 처리합니다 (출력이 발생하지 않더라도).

ps aux | tee >(grep syslog) | awk 'NR == 1'

그러나 위와 같이 선은 여전히 ​​순서가 잘못되어 나타날 수 있습니다.

ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')

이것이 너무 자세하지는 않았지만 서로 상호 작용하는 많은 동시 작업이 있기를 바랍니다. 별도의 프로세스는 동기화없이 동시에 실행되므로 특정 실행에 대한 작업은 다를 수 있습니다. 때로는 이유를 설명하기 위해 기본 프로세스를 깊이 파고 드는 데 도움이됩니다.


1
훌륭한 답변! 나는 기본 프로세스에 관심이 있기 때문에 실제로 물었다. 일이 일정하지 않을 때는 흥미 롭습니다. stdout 종료를 ps aux | tee >(grep syslog) | head -n1중지 하는 더 나은 실행 방법이 head있습니까? 와우,이 명령은 지금 출력을 제공하기 시작했지만, 당신의 대답에 따라 일어날 것처럼, 그것은 잘린 것 같습니다USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND syslog 806
Rqomey

1
대신 stdin을 닫지 않는 것을 사용할 수 있습니다 head. 이 예제로 답변을 업데이트했습니다.ps aux | tee >(grep syslog) | awk 'NR == 1'
mrb

1
@KrzysztofAdamski는을 사용할 때 >(cmd)명명 된 파이프를 생성하고이를 명령 ( tee) 의 인수로 전달합니다 . 그런 다음 teestdout (piped awk) 및 해당 인수에 쓰고 있습니다. mkfifo a_fifo ; grep ... a_fifo하나의 쉘과 ps | tee a_fifo | awk ...다른 쉘에서와 동일 합니다.
mrb

1
@KrzysztofAdamski gnu.org/software/bash/manual/html_node/… — Try echo >(exit 0)은 쉘이 전달한 실제 인수를 에코합니다 (제 경우에는 /dev/fd/63). 이것은 bash와 zsh에서 동일하게 작동합니다.
mrb

1
@mrb : 이전에 몰랐던 매우 흥미로운 기능입니다. 감사합니다. bash에서 이상한 방식으로 작동하지만 pastebin.com/xFgRcJdF를 참조하십시오 . 불행히도 지금 조사 할 시간이 없지만 내일 할 것입니다.
Krzysztof Adamski

2

grep syslog타이밍에 따라 항상 표시되는 것은 아닙니다. 셸 파이프 라인을 사용하면 거의 동시에 명령을 실행하게됩니다. 그러나 여기서 중요한 것은 "거의"라는 단어입니다. 경우 ps그렙 전에 모든 프로세스를 스캔 완료가 시작됩니다, 그것은 목록에 실 거예요. 시스템의 부하 등에 따라 임의의 결과를 얻을 수 있습니다.

티에서도 비슷한 일이 일어납니다. 서브 쉘의 백그라운드에서 실행되며 grep 전후에 실행될 수 있습니다. 이것이 출력 순서가 일치하지 않는 이유입니다.

티 질문에 관해서는, 그것은 매우 이상합니다. 일반적인 방식으로 사용되지 않기 때문입니다. 인수없이 실행되므로 데이터를 stdin에서 stdout으로 복사해야합니다. 그러나 stdout은 subshell running head (첫 번째 경우) 또는 grep (두 번째 경우)로 리디렉션됩니다. 그러나 다음 명령에도 적용됩니다. 이 경우에 발생하는 일은 실제로 구현에 달려 있다고 생각합니다. 예를 들어 내 bash 4.2.28에서 서브 쉘 stdin에는 아무것도 기록되지 않습니다. zsh에서는 시도 할 때마다 원하는대로 (PS의 첫 줄과 검색 된 줄 모두 인쇄) 안정적인 방식으로 작동합니다.


어쨌든 티가 grep 달리기를 눈에 띄게 지연시키는 것에 놀랐습니다!
Rqomey

0

약간 hackish이지만 여기에 psgrep()내가 사용 하는 쉘 함수 형태의 해결책이 있습니다.

"노이즈"행에서 발생하지 않도록 ps헤더 행을 STDERR로 옮긴 다음 grepon으로 리디렉션하고 STDOUT먼저 grep명령 자체를 제거하십시오 grep.

psgrep() { ps aux | tee >(head -1>&2) | grep -v " grep $@" | grep "$@" -i --color=auto; }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.