C++ 프로그램 내부에서 운영체제의 셸 명령을 실행하고 그 결과(출력)를 코드 안에서 직접 받아와야 하는 경우가 종종 있습니다. 예를 들어 ls 같은 시스템 명령의 결과를 문자열로 가져와 가공해야 할 때가 대표적입니다.
이럴 때 POSIX 계열 시스템(Linux, macOS 등)에서는 popen과 pclose 함수를 사용하면 간단하게 해결할 수 있습니다.
popen과 pclose란?
popen() 함수는 파이프(pipe)를 생성하고, 프로세스를 포크(fork)한 뒤, 지정한 명령을 셸(shell)을 통해 실행합니다. 이렇게 열린 파이프는 파일 스트림처럼 다룰 수 있어서, 명령의 표준 출력(stdout)을 일반 파일을 읽듯이 읽어올 수 있습니다.
명령 실행이 끝나면 반드시 pclose()를 호출하여 파이프를 닫고 프로세스가 종료될 때까지 기다려야 합니다.
구현 방법
핵심 아이디어는 다음과 같습니다.
popen()으로 명령을 실행하고 읽기 모드("r")로 파이프를 엽니다.- 버퍼를 사용해 표준 출력의 내용을 끝까지 읽으면서 결과 문자열에 계속 덧붙입니다.
pclose()로 파이프를 닫고, 누적된 결과 문자열을 반환합니다.
예제 코드
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>
using namespace std;
string exec(string command) {
char buffer[128];
string result = "";
// 명령을 실행하고 파이프 열기
FILE* pipe = popen(command.c_str(), "r");
if (!pipe) {
return "popen failed!";
}
// 프로세스 출력이 끝날 때까지 읽기
while (!feof(pipe)) {
// 버퍼로 읽어서 결과에 추가
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
int main() {
string ls = exec("ls");
cout << ls;
}실행 결과
위 프로그램을 컴파일하고 실행하면 현재 디렉터리의 파일 목록이 다음과 같이 출력됩니다.
a.out hello.cpp hello.py hello.o hydeout my_file.txt watch.py
주의 사항
popen()은 내부적으로 셸을 호출하므로, 사용자 입력을 그대로 명령 문자열에 넣으면 명령 삽입(command injection) 보안 취약점이 발생할 수 있습니다. 외부 입력은 반드시 검증하거나 제거해야 합니다.- 이 방법은 표준 출력만 읽을 수 있으며, 표준 에러(stderr)는 별도 처리가 필요합니다.
- Windows 환경에서는
_popen/_pclose라는 이름으로 유사한 기능을 제공하지만, 완전히 동일하게 동작하지 않을 수 있으므로 플랫폼별 확인이 필요합니다.