유닉스-계열 컴퓨터 운영 시스템에서, 파이프라인(pipeline)은 메시지 전달을 사용하는 프로세스-사이 통신에 대해 메커니즘입니다. 파이프라인은 각 프로세스의 출력 텍스트 (stdout)가 입력 (stdin)으로 다음 프로세스에 직접 전달하도록 표준 스트림에 의해 함께 연결된 프로세스 집합입니다. 두 번째 프로세스는 첫 번째 프로세스가 아직 실행 중일 때 시작되고, 그것들은 동시에 실행됩니다. 파이프라인의 개념은 Unix의 개발 동안 Bell Labs의 유닉스의 조상 집에서 Douglas McIlroy에 의해 옹호되며, 도구-상자 철학을 형성했습니다. 그것은 물리적 파이프라인과 유사하게 이름-지어졌습니다. 이들 파이프라인의 주요 특징은 "내부의 숨김"입니다 (Ritchie & Thompson, 1974). 이것은 차례로 시스템에서 더 명확하고 단순하게 합니다.
이 기사는 익명 파이프에 관한 것이며, 여기서 한 프로세스에 의해 작성한 데이터는 그것이 다음 프로세스에서 읽을 때까지 운영 시스템에서 버퍼링되고, 이 단방향 채널은 프로세스가 완료될 때 사라집니다. 이것은 이름-지어진 파이프와 다르며, 여기서 메시지는 파일을 만들어 이름-지어진 파이프로 또는 파이프에서 전달되고, 프로세스가 완료된 후에도 남아 있습니다. 익명 파이프에 대해 표준 쉘 구문은 수직 막대 (공통적인 Unix 용어에서 "파이프")로 구분된 여러 명령을 나열하는 것입니다.
command1 | command2 | command3
예를 들어, 현재 디렉토리에 있는 파일을 나열 (ls)하고, "key" 문자열을 포함 (grep)하는 ls 출력의 줄을 오직 유지하고, 스크롤 페이지에서 결과 (less)를 보기 위해, 사용자가 다음을 터미널의 명령줄에서 입력합니다:
ls -l | grep key | less
명령 ls -l은 프로세스로 실행되며, 그것의 출력 (stdout)은 grep key에 대해 프로세스의 입력 (stdin)으로 파이프됩니다; 그리고 less에 대해 프로세스도 마찬가지입니다. 각 프로세스는 이전 프로세스에서 입력을 취하고 표준 스트림을 통해 다음 프로세스에 대해 출력을 생성합니다. 각각 |는 운영 시스템에서 구현된 (익명) 파이프라고 하는 프로세스-사이 통신 메커니즘에 의해 왼쪽에 있는 명령의 표준 출력을 오른쪽에 있는 명령의 표준 입력에 연결하도록 쉘에 지시합니다. 파이프는 단방향입니다; 데이터는 파이프라인을 통해 왼쪽에서 오른쪽으로 흐릅니다.
Example
다음은 URL에 의해 표시되는 웹 리소스에 대해 일종의 맞춤법 검사기를 구현하는 파이프라인의 예제입니다. 그것이 하는 일에 대한 설명은 다음과 같습니다.
curl "https://en.wikipedia.org/wiki/Pipeline_(Unix)" |
sed 's/[^a-zA-Z ]/ /g' |
tr 'A-Z ' 'a-z\n' |
grep '[a-z]' |
sort -u |
comm -23 - <(sort /usr/share/dict/words) |
less
- curl은 웹 페이지의 HTML 내용을 가져옵니다 (일부 시스템에서는 wget을 사용할 수 있습니다).
- sed는 공백이나 문자가 아닌 모든 문자 (웹 페이지 콘텐츠에서)를 공백으로 바꿉니다. (줄 바꿈이 유지됩니다.)
- tr은 모든 대문자를 소문자로 변경하고 텍스트 줄의 공백을 줄 바꿈으로 변환합니다 (각 '단어'는 이제 별도의 줄에 있습니다).
- grep은 적어도 하나의 소문자 알파벳 문자를 포함한 줄만 포함합니다 (임의의 빈 줄을 제거합니다).
- sort는 '단어' 목록을 알파벳 순서로 정렬하고, -u 스위치는 중복을 제거합니다.
- comm는 두 파일 사이의 공통 줄을 찾고, -23은 두 번째 파일에 고유한 행을 표시하지 않고, 두 파일에 공통적인 줄을 표시하지 않고, 이름-지정된 첫 번째 파일에만 있는 줄을 남깁니다. 파일 이름의 자리에 -는 comm을 표준 입력으로 사용하는 (이 경우 파이프라인에서) 원인이 됩니다. sort /usr/share/dict/words는 comm이 예상하는 대로 words 파일의 내용을 알파벳순으로 정렬하고, <( ... )는 결과를 comm이 읽는 임시 파일 (프로세스 대체를 통해)로 출력합니다. 결과는 /usr/share/dict/words에서 찾을 수 없는 단어 (줄)의 목록입니다.
- less는 사용자에게 결과를 페이지로 넘길 수 있도록 합니다.
Pipelines in command line interfaces
널리 사용되는 모든 유닉스 쉘은 파이프라인 생성을 위한 특수한 구문 구조를 가집니다. 모든 사용법에서 우리는 ASCII 수직 막대 문자 |로 구분된 순서대로 명령을 씁니다 (이러한 이유로 종종 "파이프 문자"라고 불립니다). 쉘은 프로세스를 시작하고 표준 스트림 (일부 버퍼 저장소의 총량을 포함하여) 사이에 필요한 연결을 정렬합니다.
Error stream
기본적으로, 파이프라인에 있는 프로세스의 표준 오류 스트림 ("stderr")은 파이프를 통해 전달되지 않습니다; 대신, 그것들은 병합되고 콘솔로 전달됩니다. 어쨌든, 많은 쉘은 이 동작을 변경하기 위한 추가적인 구문을 가집니다. csh 쉘에서, 예를 들어, | 대신 |&를 사용하여 표준 오류 스트림이 역시 표준 출력과 병합되고 다음 프로세스에 공급되어야 함을 나타냅니다. Bourne Shell은 배시 4.0 이후의 |& 또는 2>&1을 사용하여 표준 오류를 병합하고 다른 파일로 그것을 리다이렉션할 수도 있습니다.
Pipemill
가장 공통적으로 사용된 간단한 파이프라인에서 쉘은 파이프를 통해 일련의 하위-프로세스를 연결하고, 각 하위-프로세스 내에서 외부 명령을 실행합니다. 따라서 쉘 자체는 파이프라인을 통해 흐르는 데이터를 직접 처리하지 않습니다.
어쨌든, 쉘에 대해 소위 mill 또는 pipemill을 사용하여 직접 처리를 수행하는 것이 가능합니다 (왜냐하면 while 명령은 초기 명령에서 결과를 "밀링"하는 데 사용되기 때문입니다). 이 구성은 일반적으로 다음과 같이 보일 것입니다:
command | while read -r var1 var2 ...; do
# process each line, using variables as parsed into var1, var2, etc
# (note that this may be a subshell: var1, var2 etc will not be available
# after the while loop terminates; some shells, such as zsh and newer
# versions of Korn shell, process the commands to the left of the pipe
# operator in a subshell)
done
만약 루프의 몸체가 루프의 첫 번째 반복에서 stdin:에서 읽는 cat와 ssh와 같은 명령을 포함하면 그러한 파이프밀이 의도한 대로 수행되지 않을 수 있으며, 그러한 프로그램 (the drain이라고 함)은 command로부터 남아있는 출력을 읽을 것이고, 루프는 그런-다음 종료될 것입니다 (결과는 배수관의 특성에 따라 다름). 이 동작을 방지할 수 있는 몇 가지 가능성이 있습니다. 첫째, 일부 배수관은 stdin에서 읽기를 비활성화하는 옵션을 지원합니다 (예를 들어, ssh -n). 대안적으로, 만약 배수관이 유용한 어떤 것을 수행하기 위해 stdin에서 임의의 입력을 읽을 필요가 없으면, < /dev/null을 입력으로 주어질 수 있습니다.
파이프의 모든 구성 요소가 병렬로 실행되기 때문에, 쉘은 전형적으로 내용을 처리하기 위해 하위-프로세스 (하위-쉘)를 분기하여, 외부 쉘 환경에 변수 변경을 전파하는 것을 불가능하게 만듭니다. 이 문제를 해결하기 위해, "pipemill"이 명령 대체를 포함하는 here 문서에서 대신 제공할 수 있으며, 이 문서는 내용을 통해 밀링하기 전에 실행을 완료하기 위해 파이프라인을 기다립니다. 대안적으로 이름-지어진 파이프 또는 프로세스 대체는 병렬 실행에 사용될 수 있습니다. GNU bash는 역시 마지막 파이프 구성 요소에 대해 분기를 비활성화하기 위한 lastpipe 옵션을 가집니다.
Creating pipelines programmatically
파이프라인은 프로그램 제어 아래에서 생성될 수 있습니다. 유닉스 pipe() 시스템 호출은 운영 시스템에 새로운 익명 파이프 대상을 생성하도록 요청합니다. 이것은 프로세서에서 파일 설명자를 열었던 새로운 둘: 파이프의 읽기-전용 끝, 및 쓰기-전용 끝을 초래합니다. 파이프 끝은 그것들이 검색하기 위한 능력을 가지지 않는 점을 제외하고는 정상적인 익명 파일 설명자로 보입니다.
교착-상태를 피하고 병렬-처리를 이용하기 위해, 하나 이상의 새로운 파이프를 갖는 유닉스 프로세스는 그런-다음, 일반적으로, fork()를 새로운 프로세스를 생성하기 위해 호출될 것입니다. 각 프로세스는 그런-다음 임의의 데이터를 생성하거나 소비하기 전에 사용하지 않을 파이프의 끝을 닫습니다. 대안적으로, 프로세스가 새로운 스레드를 만들고 파이프를 그들 사이에 통신하기 위해 사용합니다.
이름-지어진 파이프는 역시 mkfifo() 또는 mknod()를 사용하여 생성되고 그런-다음 그것들이 호출될 때 프로그램에 입력 또는 출력 파일로 표시될 수 있습니다. 그것들은 다중-경로 파이프를 생성되는 것을 허용하고, 표준 오류 리다이렉션, 또는 tee와 결합될 때 특히 효과적입니다.
Implementation
대부분의 유닉스-계열 시스템에서, 파이프라인의 모든 프로세스는 적절하게 연결된 스트림과 함께 동시에 시작되고, 모신에서 실행 중인 모든 다른 프로세스와 함께 스케줄러에 의해 관리됩니다. 이것의 중요한 측면, 유닉스 파이프를 다른 파이프 구현과 구별하는 설정은 버퍼링의 개념입니다: 예를 들어 보내는 프로그램은 초당 5000바이트를 생성할 수 있고, 수신 프로그램은 오직 초당 100바이트를 받아들일 수 있지만, 데이터는 손실되지 않습니다. 대신, 보내는 프로그램의 출력이 버퍼에 유지됩니다. 수신 프로그램이 데이터를 읽을 준비가 될 때, 파이프라인에서 다음 프로그램이 버퍼에서 읽습니다. 리눅스에서, 버퍼의 크기는 65,536바이트 (64KiB)입니다. 필요하다면, bfr이라고 불리우는 오픈 소스 타사 필터가 더 큰 버퍼를 제공하기 위해 사용할 수 있습니다.
Network pipes
netcat 및 socat과 같은 도구는 파이프를 TCP/IP 소켓에 연결할 수 있습니다.
History
파이프라인 개념은 Douglas McIlroy에 의해 발명되었고 버전 3 유닉스의 매뉴얼 페이지에서 처음 설명되었습니다. McIlroy는 명령 쉘이 한 프로그램의 출력 파일을 또 다른 프로그램의 입력으로 전달하는 경우가 많다는 사실을 알게 되었습니다.
그의 아이디어는 (McIlroy가 쓴 "in a feverish night") Ken Thompson이 pipe() 시스템 호출과 파이프를 셸과 버전 3 유닉스의 여러 유틸리티에 추가했을 때 1973년에 구현되었습니다. "The next day", McIlroy는 계속해서, "saw an unforgettable orgy of one-liners as everybody joined in the excitement of plumbing." McIlroy는 역시 Thompson에게 | 표기법을 공인했으며, 버전 4에서 파이프 구문의 설명을 크게 단순화했습니다.
비록 독립적으로 개발되었지만, 유닉스 파이프는 1960년대 Dartmouth Time Sharing System에 대해 Ken Lochner에 의해 개발된 '통신 파일'과 관련이 있고, 선행되었습니다.
Tony Hoare의 통신 순차 프로세스 (CSP)에서, McIlroy의 파이프가 추가로 개발되었습니다.
역시 파이프라인 개념을 반복적인 명령을 함께 연결하기 위해 사용하는 Apple의 Automator에 대해 아이콘에서 로봇은 원래 유닉스 개념에 경의를 표하는 파이프를 유지합니다.
Other operating systems
유닉스의 이 기능은 VM/CMS와 MVS의 MS-DOS와 CMS Pipelines 패키지와 같은 다른 운영 시스템에서 차용했었고, 결국 소프트웨어 엔지니어링의 파이프와 필터 설계 패턴으로 지정하게 되었습니다.
External links
- History of Unix pipe notation
- Doug McIlroy’s original 1964 memo, proposing the concept of a pipe for the first time
- pipe: create an interprocess channel – System Interfaces Reference, The Single UNIX Specification, Issue 7 from The Open Group
- Pipes: A Brief Introduction by The Linux Information Project (LINFO)
- Unix Pipes – powerful and elegant programming paradigm (Softpanorama)
- Ad Hoc Data Analysis From The Unix Command Line at Wikibooks – Shows how to use pipelines composed of simple filters to do complex data analysis.
- Use And Abuse Of Pipes With Audio Data – Gives an introduction to using and abusing pipes with netcat, nettee and fifos to play audio across a network.
- stackoverflow.com – A Q&A about bash pipeline handling.