데몬(daemon) 프로그램이 아닌 이상, 많은 프로그램(명령어)들은 데이터를 keyboard로 입력을 하거나, 그 결과를 화면의 출력으로 확인한다. 그래서 이런 경우에는 사람이 직접 수작업으로 실행하고 그 결과를 눈으로 확인하고 판단한다. 그러나 프로그램으로 이들 명령어에 keyboard를 입력하는 효과와 실행 결과를 바로 확인해서 처리할 수 있다면 운영 등에서 효율적인 작업을 할 수 있다. 물론, I/O에 대한 pattern이 어느 정도 일정해야만 하겠지만...

 

    이를 가능하게 해주는 함수가 바로 popen(3) / pclose(3) 및 stdio.h에 있는 stream I/O 함수들이다. fopen(3) / fclose(3)함수가 파일을 open하고 close한다면, popen(3) / pclose(3)는 명령어를 실행시키고 실행된  process와 표준 입/출력으로 대화창을 열어주는 함수이다. 열려진 대화창은 fopen(3)으로 open한 파일처럼 fread(3)/fwrite(3)/fgets(3)/fprintf(3)... 등의 함수를 통해서 I/O를 하게된다.

 


함수 사용법

 

popen(3) : pipe open - 함수 사용법

#include <stdio.h>

FILE *popen(const char *command, const char *type);

설명 
    실행시킨 명령어와 표준입력/표준출력을 주고 받기 위한 용도로 사용함. 
       (Input/Output pipe를 open하기 위한 용도로 사용함)

parameter
    command : 실행할 명령어
    type : "r" 또는 "w"
         "r" : 명령어를 실행하면 명령어가 표준출력으로 출력한 문자열을 읽기 위한 용도로 pipe를 open함
         "w" : 명령어를 실행 후 사용자가 keyboard로 데이터를 입력해야 하는 명령어에 사용함. 
               즉, command의 표준입력으로 데이터를 전송하기 위한 pipe를 open함

return
    정상이면 NULL이 아닌 FILE *
    실패이면 NULL
    

 


 

pclose(3) : pipe close - 함수 사용법

#include <stdio.h>

int pclose(FILE *stream);

설명
    open된 pipe를 close 함

parameter
    popen()에 의해 열려진 FILE *

return

    정상이면 -1이 아닌 값
    실패이면 -1

 

 


사용 예제

 

Example 1). 
읽기용 pipe open(명령어의 출력값을 읽기용)
ls -al 명령어는 실행후에 추가적인 keyboard 입력없이 결과만 출력하고 끝납니다.
이와 같이 그 명령어에서 출력하는 결과만 프로그램 내에서 읽고 활용하고 싶을 때의 예제 

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *fp = NULL;
    char line[10240];

    /* 명령어 수행에 대한 pipe를 호출함 */
    if((fp = popen("ls -al", "r")) == NULL) {
        return 1;
    }

    /* ls -al 명령어로 출력하는 내용을 한줄씩 읽어서 처리하는 함 */
    while(fgets(line, 10240, fp) != NULL) {
        printf("%s", line);
    }

    pclose(fp);
    return 0;
}

 

실행결과

drwxrwxr-x 2 developer developer 46 7월 8 11:27 .
drwxrwxr-x 8 developer developer 74 7월 8 10:52 ..
-rwxrwxr-x 1 developer developer 8714 7월 8 11:26 popen-sample
-rw-rw-r-- 1 developer developer 280 7월 8 11:26 popen-sample.c

 


 

Example 2).
write용 pipe open(명령어의 입력값으로 쓰기용)
gdb로 core file이 생성되었을 때, 일괄로 분석 파일을 만드는 예제이다.
gdb는 오류 위치를 알기 위해서 where[enter]를 입력하고 
종료를 위해서는 quit[enter]를 입력해야만 결과를 알 수 있으며, 그 결과 내용은 redirectory로 파일로 output 처리합니다.

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *fp = NULL;

    if((fp = popen("gdb test core-test-20160707 > core-test-20160707.txt", "w")) == NULL) {
        return 1;
     }

    // 오류 위치에 대한 로그를 생성하라는 명령어 전달
    fprintf(fp, "where\n");

    // gdb를 종료하라는 명령어 전달
    fprintf(fp, "quit\n");

    pclose(fp);
    return 0;
}

 

 

실행결과: (core-SAMPLE-20160707.txt 파일의 내용)

GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-64.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
...중략...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `SAMPLE -b -21382 -s SAMPLE -d -1 -e $(SVR).$(CDATE).log -o $(SVR).$(CDATE).'.
Program terminated with signal 11, Segmentation fault.
#0 0x00002aee04797480 in do_lookup_x () from /lib64/ld-linux-x86-64.so.2
Missing separate debuginfos, use: debuginfo-install glibc-2.17-105.el7.x86_64 libaio-0.3.109-12.el7.x86_64 libgcc-4.8.5-4.el7.x86_64 numactl-libs-2.0.9-4.el7.x86_64
(gdb) <-- where[enter] 입력부분 #0 0x00002aee04797480 in do_lookup_x () from /lib64/ld-linux-x86-64.so.2
...중략...
#6 0x00002aee04797ccb in do_lookup_x () from /lib64/ld-linux-x86-64.so.2
#7 0x00002aee04797faf in _dl_lookup_symbol_x () from /lib64/ld-linux-x86-64.so.2
#8 0x00002aee0479c8b6 in _dl_profile_fixup () from /lib64/ld-linux-x86-64.so.2
#9 0x00002aee047afcb8 in ?? ()
#10 0x000000000000004f in ?? ()
#11 0x00002aee049c0a93 in sample_func (signo=<error reading variable: Cannot access memory at address 0xfffffffffffff15c>) at sample.c:2479
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) <-- quit[enter] 입력부분

 


 

Example 3).
그런데, 프로그램과 대화형으로 주고받고를 해야 하는 경우에는 어떻게 해야 할까요?

예를들면 입력하고 결과를 받고 결과를 해석한 후에 경우에 따라 다른 값을 전달하고 주거니 받거니 해야하는 경우에는 어떻게 해야할까요? (잘 없을 것 같긴한데....)

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *fp = NULL;
    FILE *fp2 = NULL;
    char line[10240];


    if((fp = popen("command > command.txt", "w")) == NULL) {
        return 1;
    }
    if((fp2 = fopen("command.txt", "r")) != NULL) {
        return 1;
    }

    // command의 결과 파일인 command.txt가 필요없으면 파일이 열린 상태에서
    // unlink("command.txt"); 함수를 실행한다.

    fprintf(fp, "명령어\n");

    while(1) {
        fgets(line, 10240, fp2);
        // 문자열 분석후에 
        if(line의 내용에 따라1 ) {
            fprintf(fp, "명령어1\n");
        } else if(line의 내용에 따라2 ) {
            fprintf(fp, "명령어2\n");
        } else  ... {
          ....
        }
    }

    pclose(fp);
    fclose(fp2);

    return 0;
}

 

 


 

see also :  popen(3) pclose(3)

블로그 이미지

사용자 자연&사람

행복한 개발자 programmer since 1995.

Tag , ,

댓글을 달아 주세요