나는 쉘이 실제로 파이프된 명령을 어떻게 실행하는지 생각해 본 적이 없습니다. 나는 항상 "프로그램의 표준 출력은관로파이프에 대해 생각하는 방식으로 다른 사람의 stdin"에 넣습니다. 따라서 자연스럽게 이 경우 가 먼저 실행된 다음 A | B
의 stdout을 가져오고 stdout을 입력으로 사용한다고 생각했습니다. A
B
A
A
그러나 나는 사람들이 에서 특정 프로세스를 검색할 때 해당 프로세스가 최종 출력에 나타나지 않도록 하기 위해 명령 끝에 프로세스를 포함시키는 ps
것을 발견했습니다. 이는 명령이 실행 중이고 따라서 의 출력에 포함된다는 암시적 지식이 명령에 있음 을 의미합니다 . 그러나 출력이 파이프로 연결되기 전에 완료 되면 실행 중인지 어떻게 알 수 있습니까 ?grep -v "grep"
grep
ps aux | grep "bash" | grep -v "grep"
ps
grep
ps
ps
grep
grep
flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY TIME CMD
3773 pts/0 00:00:00 bash
3784 pts/0 00:00:00 ps
3785 pts/0 00:00:00 grep
답변1
파이프라인 명령이 동시에 실행됩니다. 실행할 때 먼저 시작하는지 여부는 ps | grep …
운의 문제(또는 셸 작업의 세부 사항과 커널 내부 스케줄러의 미세 조정의 문제)에 달려 있으며 어떤 경우에도 계속 시작됩니다. 동시에 실행됩니다.ps
grep
이는 첫 번째 프로그램이 작업을 완료하기 전에 두 번째 프로그램이 첫 번째 프로그램의 데이터를 처리할 수 있도록 하는 데 매우 일반적으로 사용됩니다. 예를 들어
grep pattern very-large-file | tr a-z A-Z
grep
대용량 파일 탐색이 완료되기 전에도 일치하는 줄을 대문자로 표시하기 시작합니다.
grep pattern very-large-file | head -n 1
grep
일치하는 첫 번째 줄을 표시하고 입력 파일 읽기를 마치기 전에 처리를 중지할 수 있습니다.
파이프라인 프로그램이 순차적으로 실행된다는 내용을 읽었다면 이 문서를 벗어나세요. 파이프라인 프로그램은 항상 동시에 실행됩니다.
답변2
명령이 실행되는 순서는 실제로 중요하지 않으며 보장되지 않습니다. pipe()
, fork()
, 및 dup()
의 난해한 세부 사항은 제쳐두고 execve()
셸은 먼저 프로세스 간에 데이터가 흐르는 파이프인 파이프를 만든 다음 파이프의 각 끝이 프로세스에 연결된 프로세스를 만듭니다. 실행 중인 첫 번째 프로세스는 두 번째 프로세스의 입력을 기다리는 것을 차단하거나 두 번째 프로세스가 파이프에서 데이터 읽기를 시작할 때까지 기다리는 것을 차단할 수 있습니다. 이러한 대기 시간은 임의로 길어질 수 있지만 문제가 되지 않습니다. 프로세스가 어떤 순서로 실행되든 결국 데이터는 전송되고 모든 것이 잘 작동합니다.
답변3
죽은 말의 위험에 처한 오해는 다음과 같습니다.
ㅏ|두번째
동등하다
ㅏ>임시 파일 두번째<임시 파일 RM임시 파일
그러나 유닉스가 만들어졌을 당시에는 아이들이 공룡을 타고 학교에 가고 있었고 디스크가 너무 작아서 상당히 순한 명령이 파일 시스템의 사용 가능한 공간을 모두 소모하는 경우가 많았습니다. 그렇다면 B
파이프라인의 최종 출력은 다음과 같을 수 있습니다.grep some_very_obscure_string
많은중간 파일보다 작습니다. 따라서 파이프라인 개발은 "실행"을 줄여서 사용하지 않습니다.ㅏ먼저 실행한 다음두번째입력은 다음에서 제공됩니다.ㅏ'출력' 모델이지만 B
실행을 병렬화 A
하고 중간 파일을 디스크에 저장할 필요가 없도록 하는 방법입니다.
답변4
귀하는 주문에 관해 질문하셨는데, 제 생각에는 그것이 이 문제에서 매우 중요한 측면이라고 생각합니다. 그것은 무작위가 아닙니다 (Giles가 그의 대답에서 말하려고 한 것처럼).
ps -ef
다음으로 파이프되는 명령은 다음과 같습니다 grep
.
$ ps -ef | grep .
...
alexis 37188 55443 0 20:17 pts/4 00:00:00 ps -ef
alexis 37189 55443 0 20:17 pts/4 00:00:00 grep --color=auto .
...
참고: 문제에 중요하지 않은 다른 모든 프로세스를 출력에서 제거했습니다.
보시다시피 ps -ef
출력에는 a와 a가 있습니다. grep --color=auto .
이제 질문에 답해주실 수 있나요?
예. 이 ps
명령의 PID는 37,188이고 grep
이 명령의 PID는 37,189입니다. 분명히 왼쪽에서 오른쪽으로 생성되며 어떤 쉘도 이 작업을 다르게 수행해서는 안 됩니다.
기술적으로 C에서는 다음을 사용하여 파이프를 만듭니다.pipe(2)
이 함수는 두 개의 파일 설명자를 제공합니다. 하나 stdout
는 에서 사용되고 다른 하나 는 에서 ps
사용됩니다 . 를 시작하기 전에 파일 설명자를 예약하는 것은 쉽습니다 .stdin
grep
stdin
ps
또한 다음과 같은 시스템 구성을 보면:
$ getconf -a | grep PIPE_BUF
PIPE_BUF 4096
_POSIX_PIPE_BUF 4096
이 두 매개변수는 파이프의 최소 보장 크기(바이트)를 정의합니다. Linux 2.6부터 기본 크기는 64Kb입니다. 또한 절대 최대 바이트 수는 다음과 같이 정의됩니다.
$ cat /proc/sys/fs/pipe-max-size
1048576
이것이 1Mb임을 알 수 있습니다. 파이프가 가득 차면 출력기( ps
첫 번째 예에서)는 파이프 반대편의 프로세스가 데이터( grep
첫 번째 예에서)를 읽을 때까지 차단됩니다.
즉, 출력이 ps
파이프 크기보다 훨씬 작기 때문에 다음과 같습니다.
$ ps -ef | wc
1132 10819 121435
(즉, 현재 내 컴퓨터의 출력은 약 120Kb입니다...)
배관이 전혀 막히지 않습니다.
1Mb를 초과하는 스트리밍 데이터의 경우 어느 시점에서 차단됩니다. grep
즉시 시작하지 않으면 첫 번째 명령의 호출이 차단되므로 절대 시작되지 않습니다 write()
.
따라서 프로세스는 매우 빠르게 연속적으로 시작되지만 대부분의 경우 병렬로 실행됩니다(또는 단일 프로세서가 있는 경우 동시에). 즉, ps
명령이 먼저 종료됩니다. 이는 파이프를 "완료"( EOF
데이터를 읽을 때 신호를 받음)로 표시하고, 이것이 다음 도구가 파이프가 완료되었음을 아는 방법이며, 수신한 마지막 몇 바이트를 처리하면 파이프도 죽습니다.
반대로, 파이프의 오른쪽 프로세스가 일찍 종료되면(왼쪽 프로세스가 파이프에 쓰기를 완료하기 전에) 왼쪽 프로세스는 SIGPIPE
파이프에 쓰기를 시도하자마자 신호를 받습니다. 이는 파이프라인의 프로세스가 종료되는 경우 파이프라인도 빠르게 종료되도록 하기 위해 수행됩니다.