openstdin, stdout, stderr 방향 전환을 제어하는 방법?
저는 popen()이 유닉스에서 자식 프로세스의 stdin, stdout 및 stderr을 어떻게 리디렉션하는지에 대해 혼란스럽습니다.popen()의 man 페이지는 이와 관련하여 매우 명확하지 않습니다.더콜
FILE *p = popen("/usr/bin/foo", "w");
자식 프로세스를 포크하고 "-c", "/usr/bin/foo" 인수가 있는 셸을 실행하고 이 셸의 stdin(foo의 stdin으로 리디렉션됨)을 stdout 상단으로 리디렉션합니다.하지만 stderr는 어떻게 됩니까?그 이면의 일반적인 원리는 무엇입니까?
foop에서 파일을 열었을 때(fopen, socket, accept 등을 사용) 부모 프로세스에 stdout이 없으면 다음 사용 가능한 파일 번호가 1 등으로 할당되는 것을 확인했습니다.이는 fprintf(stderr, ...)와 같은 호출에서 예상치 못한 결과를 제공합니다.
글로 피할 수 있습니다.
FILE *p = popen("/usr/bin/foo 2>/dev/null", "w");
부모 프로그램에서, 하지만 그들의 더 나은 방법은?
popen(3)
단지 도서관 기능일 뿐입니다.fork(2)
그리고.pipe(2)
진짜 일을 하기 위해서 입니다.
하지만pipe(2)
단방향 파이프만 만들 수 있습니다.자식 프로세스 입력을 보내고 출력을 캡처하려면 파이프 두 개를 열어야 합니다.
만약 당신이 캡처하고 싶다면.stderr
그것도 가능하지만 그럼 파이프 세 개가 필요하고, 그리고 한 개가 필요합니다.select
루프를 사용하여 읽기를 중재합니다.stdout
그리고.stderr
냇물
여기 두 개의 파이프 버전에 대한 예가 있습니다.
간단한 아이디어: 명령 문자열에 "2>&1"을 추가하여 bash를 stderr을 stdout으로 리디렉션하도록 강제하는 것은 어떨까요(좋아, stdin에 쓰는 것은 여전히 불가능하지만 적어도 우리는 stderr과 stdout을 우리의 C 프로그램에 얻습니다).
popen()의 반환 값은 fclose(3)가 아닌 pclose()로 닫아야 한다는 점을 제외하면 모든 면에서 정상 표준 I/O 스트림입니다.이러한 스트림에 기록하는 것은 명령어의 표준 입력에 기록합니다. 명령어의 표준 출력은 명령어 자체에 의해 변경되지 않는 한 popen()이라는 프로세스의 출력과 동일합니다.반대로 "opened" 스트림에서 읽게 되면 명령의 표준 출력이 읽혀지고 명령의 표준 입력은 popen()이라는 프로세스의 입력과 동일합니다.
manpage에서 명령 표준 출력을 읽거나 표준 입력에 쓸 수 있습니다.stderr에 대해서는 아무것도 나와있지 않습니다.따라서 이는 재연결되지 않습니다.
"w"를 입력하면 실행되는 셸의 stdin으로 당신의 물건을 보냅니다.그래서 하는 것은
FILE * file = popen("/bin/cat", "w");
fwrite("hello", 5, file);
pclose(file);
에서 /bin/cat 합니다 합니다."hello"
표준 입력 스트림으로서.를 들어 어 stderr오로 재연결하십시오."foo"
위의 코드를 실행하기 전에 먼저 이 작업을 수행합니다.
FILE * error_file = fopen("foo", "w+");
if(error_file) {
dup2(fileno(error_file), 2);
fclose(error_file);
}
파일을 열고 파일 설명자를 2로 복제하여 원래 파일 설명자를 닫습니다.
open
1을 얻을 것입니다. 그것은 (stdin이 이미 열려 있는 경우) 다음 무료 파일 descriptor이기 때문입니다.내가 볼 수 있는 유일한 해결책은 위의 코드처럼 dup2를 사용하고 무언가를 부모에 있는 것으로 복제하는 것입니다.하십시오.stdout
, 그것은 성공하지 못할 것입니다.stdout
부모에게도 열려 있습니다.그곳은 닫혀있습니다.
바트 트로이아노프스키의 팝펜 RWE를 확인해보세요.3개의 파이프를 모두 깨끗하게 하는 방법.
STDERR만 얻고 싶다면 다음을 시도해 보십시오.
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
/*
* Pointer to array allocated at run-time.
*/
static pid_t *childpid = NULL;
/*
* From our open_max(), {Prog openmax}.
*/
static int maxfd;
FILE *
mypopen(const char *cmdstring, const char *type)
{
int i;
int pfd[2];
pid_t pid;
FILE *fp;
/* only allow "r" "e" or "w" */
if ((type[0] != 'r' && type[0] != 'w' && type[0] != 'e') || type[1] != 0) {
errno = EINVAL; /* required by POSIX */
return(NULL);
}
if (childpid == NULL) { /* first time through */
/* allocate zeroed out array for child pids */
maxfd = 256;
if ((childpid = calloc(maxfd, sizeof(pid_t))) == NULL)
return(NULL);
}
if (pipe(pfd) < 0)
return(NULL); /* errno set by pipe() */
if ((pid = fork()) < 0) {
return(NULL); /* errno set by fork() */
} else if (pid == 0) { /* child */
if (*type == 'e') {
close(pfd[0]);
if (pfd[1] != STDERR_FILENO) {
dup2(pfd[1], STDERR_FILENO);
close(pfd[1]);
}
} else if (*type == 'r') {
close(pfd[0]);
if (pfd[1] != STDOUT_FILENO) {
dup2(pfd[1], STDOUT_FILENO);
close(pfd[1]);
}
} else {
close(pfd[1]);
if (pfd[0] != STDIN_FILENO) {
dup2(pfd[0], STDIN_FILENO);
close(pfd[0]);
}
}
/* close all descriptors in childpid[] */
for (i = 0; i < maxfd; i++)
if (childpid[i] > 0)
close(i);
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127);
}
/* parent continues... */
if (*type == 'e') {
close(pfd[1]);
if ((fp = fdopen(pfd[0], "r")) == NULL)
return(NULL);
} else if (*type == 'r') {
close(pfd[1]);
if ((fp = fdopen(pfd[0], type)) == NULL)
return(NULL);
} else {
close(pfd[0]);
if ((fp = fdopen(pfd[1], type)) == NULL)
return(NULL);
}
childpid[fileno(fp)] = pid; /* remember child pid for this fd */
return(fp);
}
int
mypclose(FILE *fp)
{
int fd, stat;
pid_t pid;
if (childpid == NULL) {
errno = EINVAL;
return(-1); /* popen() has never been called */
}
fd = fileno(fp);
if ((pid = childpid[fd]) == 0) {
errno = EINVAL;
return(-1); /* fp wasn't opened by popen() */
}
childpid[fd] = 0;
if (fclose(fp) == EOF)
return(-1);
while (waitpid(pid, &stat, 0) < 0)
if (errno != EINTR)
return(-1); /* error other than EINTR from waitpid() */
return(stat); /* return child's termination status */
}
int shellcmd(char *cmd){
FILE *fp;
char buf[1024];
fp = mypopen(cmd,"e");
if (fp==NULL) return -1;
while(fgets(buf,1024,fp)!=NULL)
{
printf("shellcmd:%s", buf);
}
pclose(fp);
return 0;
}
int main()
{
shellcmd("ls kangear");
}
그리고 당신은 이것을 얻게 될 것입니다.
shellcmd:ls: cannot access kangear: No such file or directory
언급URL : https://stackoverflow.com/questions/280571/how-to-control-popen-stdin-stdout-stderr-redirection
'bestsource' 카테고리의 다른 글
ID별 워드프레스 사용자 프로파일 URL/링크 가져오기 (0) | 2023.10.01 |
---|---|
요소/문서에 첨부된 자바스크립트 이벤트 청취자/처리자가 있는지 확인하는 방법? (0) | 2023.10.01 |
C 휘발성 변수와 캐시 메모리 (0) | 2023.10.01 |
C에서 전역 변수는 항상 0으로 초기화됩니까? (0) | 2023.10.01 |
a = 0, b = a++, c = a++의 정의가 C에 정의된 동작을 가지고 있습니까? (0) | 2023.10.01 |