다음 위로 이전 목차 리눅스 프로그래머를 위한 가이드

6.2.3 파이프 쉬운 방법! (pipes the Easy Way!)

앞의 두서없는 글들이 파이프를 만들고 사용하는 매우 무난한 방법처럼 보였다면, 또 다른 것이 있다.
  LIBRARY FUNCTION: popen();                                                    

  PROTOTYPE: FILE *popen ( char *command, char *type);                          
    RETURNS: 성공시 새로운 파일 스트림(stream)                                       
             fork(),pipe()호출이 실패했을 때 널(NULL)

  NOTES: 명령어("command")를 사용하여 파이프를 만들고 fork/exec를 수행한다.

이 표준 라이브러리 함수는 내부적으로 pipe()를 호출하여 반이중 파이프라인을 만든다. 쉘에서 자식 프로세스를 생성(fork)하고, 본 쉘(Bourne ahell)을 exec하고 "command" 아규먼트를 실행한다. 자료 흐름의 방향은 두번째 아뮤먼트인 "type"에 의해 결정된다. "read"이나 "write"에 대해 "r"이나 "w"가 될 수 있다. 두가지가 모두 될 수는 없다. 리눅스에서, 파이프는 "type"의 첫번째 글자에 의해 지정된 모드로 열려진다. 따라서, "rw"를 넘긴다면 읽기("read") 모드로 열려진다.

이 라이브러리 함수가 당신을 위해 까다로운 일을 수행하는 동안, 중요한 흥정(tradeoff)이 일어난다. pipe() 시스템 호출을 사용하고 fork/exec를 취급하는 것에 의해 당신은 잠시 통제권을 잃어버린다. 본 쉘이 직접 사용되므로, "command" 아규먼트 내에서 와일드 카드(wildcard)를 포함한 쉘 메타문자 확장(shell metacharacter expansion)이 가능하다.

popen()에 의해 만들어진 파이프는 pclose()로 닫아야만 한다. popen/pclose가 표준 파일 스트림 I/O 함수인 fopen(),fclose()와 매우 비슷하다는 것을 알았을 것이다.


 LIBRARY FUNCTION: pclose();                                                   

  PROTOTYPE: int pclose( FILE *stream );                                        
    RETURNS: wait4() 호출의 탈출 상태(exit status)
             -1 스트림("stream")이 유효하지 않거나 wait4()가 실패했으면 

  NOTES: 파이프 프로세스가 종료되기를 기다렸다가 스트림을 닫는다.

pclose() 함수는 popen()에 의해 생성(fork)된 프로세스에 대해 wait4()를 수행한다. wait4()로부터 반환될 때, 파이프와 파일 스트림을 파괴한다. 일반적인 스트림에 기초한 파일 I/O에 대한 fclose() 함수와 동의어라 할 수 있다.

sort명령어로 파이프를 열어 문자열의 배열을 정렬처리하는 예제를 살펴보자:

/*****************************************************************************
 리눅스 프로그램머를 위한 가이드 - 6장 에서 발췌
 (C)opyright 1994-1995, Scott Burkett
 ***************************************************************************** 
 MODULE: popen1.c
 *****************************************************************************/
  
#include <stdio.h>

#define MAXSTRS 5

int main(void)
{
        int  cntr;
        FILE *pipe_fp;
        char *strings[MAXSTRS] = { "echo", "bravo", "alpha",
                                  "charlie", "delta"};

	/*popen() 호출을 사용하여 단방향 파이프를 만든다*/
        if (( pipe_fp = popen("sort", "w")) == NULL)
        {
                perror("popen");
                exit(1);
        }

	/*반복 처리*/
        for(cntr=0; cntr<MAXSTRS; cntr++) {
                fputs(strings[cntr], pipe_fp);
                fputc('\n', pipe_fp);
        }

	/*파이프를 닫는다*/
        pclose(pipe_fp);
        
        return(0);
}
popen()는 자신의 명령을 수행하는데 쉘을 사용함으로, 모든 쉘 확장 문자들과 메타문자의 사용이 가능하다. 더군다나 redirection과 같은 보다 진보된 기술과 파이프의 출력조차 popen()에서 사용될 수 있다. 다음의 간단한 호출을 살펴보자:
        popen("ls ~scottb", "r");
        popen("sort > /tmp/foo", "w");
        popen("sort | uniq | more", "w");
popen()의 또 다른 예인, 두개의 파이프(하나는 ls, 다른 하나는 sort)를 여는 작은 프로그램을 살펴보자:

/*****************************************************************************
 리눅스 프로그램머를 위한 가이드 - 6장 에서 발췌
 (C)opyright 1994-1995, Scott Burkett
 ***************************************************************************** 
 MODULE: popen2.c
 *****************************************************************************/

#include <stdio.h>

int main(void)
{
        FILE *pipein_fp, *pipeout_fp;
        char readbuf[80];

	/*popen() 호출을 사용하여 단방향 파이프를 만든다*/
        if (( pipein_fp = popen("ls", "r")) == NULL)
        {
                perror("popen");
                exit(1);
        }

	/*popen() 호출을 사용하여 단방향 파이프를 만든다*/
        if (( pipeout_fp = popen("sort", "w")) == NULL)
        {
                perror("popen");
                exit(1);
        }

	/*반복 처리*/
        while(fgets(readbuf, 80, pipein_fp))
                fputs(readbuf, pipeout_fp);

	/*파이프를 닫는다*/
        pclose(pipein_fp);
        pclose(pipeout_fp);

        return(0);
}
popen()의 마지막 예제를 위해, 넘겨받은 명령어와 파일명간의 파이프라인을 여는 일반적인 프로그램을 작성해 보자:
/*****************************************************************************
 리눅스 프로그래머를 위한 가이드 - 6장 에서 발췌
 (C)opyright 1994-1995, Scott Burkett
 ***************************************************************************** 
 MODULE: popen3.c
 *****************************************************************************/

#include <stdio.h>

int main(int argc, char *argv[])
{
        FILE *pipe_fp, *infile;
        char readbuf[80];

        if( argc != 3) {
                fprintf(stderr, "USAGE:  popen3 [command] [filename]\n");       
                exit(1);
        }

	/*입력 파일을 연다*/
        if (( infile = fopen(argv[2], "rt")) == NULL)
        {
                perror("fopen");
                exit(1);        
        }

	/*popen() 호출을 사용하여 단방향 파이프를 만든다*/
        if (( pipe_fp = popen(argv[1], "w")) == NULL)
        {
                perror("popen");
                exit(1);
        }

	/*반복 처리*/
        do { 
                fgets(readbuf, 80, infile);
                if(feof(infile)) break;

                fputs(readbuf, pipe_fp);
        } while(!feof(infile));

        fclose(infile); 
        pclose(pipe_fp);

        return(0);
}
다음의 예를 가지고 이 프로그램을 수행시켜보자:
        popen3 sort popen3.c
        popen3 cat popen3.c
        popen3 more popen3.c
        popen3 cat popen3.c | grep main


이전:6.2.2 C로 파이프 만들기 다음:6.2.4 파이프의 Atomic 동작

Copyright (c) 1996,1997 by Euibeom.Hwang & SangEun.Oh All Rights Reserved

Email To:Webmaster , Another address
LAST UPDATE Nov 18,1997
Created Nov 15,1997