Search
Duplicate

pipex 명령어 사용 예시들

간단소개
pipex 기본 함수는 이런 거구나..하기 위한 간단 예시들
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C
42cursus
42seoul
Scrap
태그
명령어
기초
c언어
9 more properties

목차

environ
perror
fork
waitpid
dup2
pipe
execve

1. environ (사실 함수는 아니지만...)

예시 코드

#include <stdio.h> extern char **environ; //int main(int argc, char *argv[], char *envp[]) int main(int argc, char *argv[]) { int idx = 0; (void)argc; (void)argv; while (environ[idx]) { printf("environ[%d]: %s\n", idx, environ[idx]); idx++; } return (0); }
C
복사
C에서 환경변수는 크게 2가지 형태로 받아올 수 있다. 위와 같이 extern 변수로 받아오는 방법, 주석과 같이 argc, argv와 함께 main의 인자로 받아오는 방법. gnu.org 레퍼런스에 따르면 3-argument 형태가 posix 표준이 아니라고 되어있다.
POSIX.1 does not allow this three-argument form, so to be portable it is best to write main to take two arguments, and use the value of environ.
참고 링크

2. perror

프로토타입

#include <stdio.h> void perror(const char *s);
C
복사

예시 코드

#include <stdio.h> #include <errno.h> int main(void) { perror("before error"); errno = ENOMEM; perror("errno = ENOMEM"); errno = EACCES; perror("errno = EACCES"); errno = ENOENT; perror("errno = ENOENT"); errno = ENOTDIR; perror("errno = ENOTDIR"); errno = EFAULT; perror("errno = EFAULT"); errno = EBADF; perror("errno = EBADF"); return (0); }
C
복사
errno 변수와 각각의 매크로는 <errno.h>에 있다.
perror는 errno에 해당하는 에러 메세지를 표준에러에 출력해준다. 인자로 문자열을 넣으면 “문자열: 에러메세지” 형태로 출력되고, NULL 포인터를 인자로 넣어주면 에러메세지만 출력된다.

3. fork

프로토타입

#include <unistd.h> pid_t fork(void);
C
복사

예시 코드

#include <unistd.h> #include <stdio.h> int main(void) { printf("pid before fork: %d\n", getpid()); pid_t newpid = fork(); if (newpid < 0) { perror(NULL); return (1); } if (newpid == 0) { printf("this is child process. child's pid: %d\n", getpid()); printf("newpid from child: %d\n", newpid); } else { printf("this is parent process. parent's pid: %d\n", getpid()); printf("newpid from parent: %d\n", newpid); } printf("this is common part\n"); return (0); }
C
복사
새로운 프로세스를 생성해주는 함수. fork를 호출한 프로세스를 부모 프로세스, 새로 생긴 프로세스를 자식 프로세스라고 한다.
실패할 경우 자식 프로세스는 생성되지 않고, 부모 프로세스에게 음수를 반환해준다 (newpid < 0)
성공할 경우 부모 프로세스에게는 새로 생성된 자식 프로세스의 pid를, 자식프로세스에게는 0을 반환해준다.
즉 자식 프로세스는 newpid == 0인 조건문을, 부모 프로세스는 else의 경우를 실행하게 된다.
부모의 pid는 fork 이전의 pid와 같고, 새로 생긴 자식 프로세스의 아이디를 newpid값으로 갖고 있다.
자식의 pid는 부모가 가지고 있는 newpid의 값과 같고, 자식이 갖고 있는 newpid라는 변수의 값은 0임을 확인할 수 있다. 조건문이 끝난 후 공통 부분은 자식, 부모 프로세스 모두 실행하게 된다.

4. waitpid

프로토타입

#include <sys/wait.h> pid_t waitpid(pid_t pid, int *stat_loc, int options);
C
복사

예시 코드

#include <sys/wait.h> #include <stdio.h> #include <unistd.h> int main(void) { pid_t pid; //int state = 0; //pid_t ret; pid = fork(); if (pid == 0) { sleep(1); /* ret = waitpid(-1, &state, 0); */ /* perror("child"); */ printf("this is child\n"); } else { /* ret = waitpid(pid, &state, 0); */ /* perror("parent"); */ /* printf("child pid: %d\n", ret); */ printf("this is parent\n"); } return (0); }
C
복사
원래 fork된 각각의 프로세스는 병렬적으로 실행되고, 순서가 보장되지 않는다. 그래서 child에 sleep을 걸어두고 실행하면 부모 프로세스가 먼저 실행되고 종료된 후 차일드 프로세스가 나중에 실행되는 것을 확인할 수 있다. waitpid를 이용해 첫번째 인자 pid에 해당하는 프로세스가 종료될 때까지 기다리게 할 수 있다.
pid: 양의 정수면 해당 프로세스를 기다리고, -1 이면 아무 자식 프로세스, 0의 경우 같은 프로세스그룹의 자식 프로세스를 기다린다. -1 보다 작은 정수의 경우 “프로세스 그룹 id = |pid|”인 프로세스를 기다린다고 한다...(이렇게 써보진 않았다)
state: 종료된 프로세스의 상태를 int로 받아온다. 이후 WIFEXITED, WIFSIGNALED, WEXITSTATUS, WTERMSIG 등의 매크로 함수를 이용해 종료 코드나, 시그널 등을 확인할 수도 있다.
options는 0, WNOHANG, WUNTRACED 등이 있다.
waitpid는 종료된 프로세스의 pid를 반환하며, 에러나 기다릴 자식 프로세스가 없는 경우 음수를 반환한다.
위의 주석을 제거하고 실행할 경우, 자식 프로세스는 기다릴 프로세스가 없으므로 No child processes 에러가 나오며, 부모는 정상적으로 자식프로세스가 종료되었으므로 자식 프로세스의 pid를 받아와서 출력한다.

5. dup2

프로토타입

#include <unistd.h> int dup2(int fildes, int fildes2);
C
복사

예시 코드

#include <unistd.h> #include <stdio.h> #include <fcntl.h> int main(void) { int fd = open("newfile", O_RDWR | O_CREAT, 0644); printf("printf before dup2\n"); dup2(fd, STDOUT_FILENO); printf("printf after dup2\n"); close(fd); return (0); }
C
복사
file descriptor를 복사한다. 위의 경우 dup2 이전에는 printf가 표준출력, 터미널에 메세지를 출력하지만, dup2이후에는 printf가 터미널이 아닌 fd 에 해당하는 newfile에 메세지를 쓰게 된다.
성공시 새 file descriptor를, 실패시 -1을 반환한다.

6. pipe

프로토타입

#include <unistd.h> int pipe(int fildes[2]);
C
복사

예시 코드

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(void) { int pipefd[2]; pipe(pipefd); pid_t child_pid = fork(); if (child_pid == 0) { close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); printf("this is child\n"); } else { close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); char *buff = calloc(100, sizeof(char)); read(0, buff, 10); printf("this is parent, read from pipe: %s\n", buff); free(buff); } return (0); }
C
복사
pipe 함수는 이름 그대로 pipe를 생성하고...fd를 할당해준다. pipe는 쓰는 쪽과 읽는 쪽, 2개의 fd가 할당되며 할당된 fd는 인자로 넣어준 int 배열 fildes에 담기게 된다. pipefd[1]쪽에 써서 pipefd[0]에서 읽을 수 있다. 한 개의 프로세스 내에서 pipe를 이용할 수 도 있지만 주로 프로세스 사이에 데이터를 주고받기 위해 이용된다.
pipe 함수는 성공시 0, 실패시 -1을 반환한다.
위 코드에서 자식 프로세스에서 pipefd[1]에 메세지를 쓰면 부모 프로세스에서 pipefd[0]을 통해 읽어올 수 있다.

7. execve

프로토타입

#include <unistd.h> int execve(const char *path, char *const argv[], char *const envp[]);
C
복사

예시 코드

#include <unistd.h> #include <stdio.h> extern char **environ; int main(void) { char *path = "/bin/ls"; char *cmd[5]; cmd[0] = "asdfasdf"; cmd[1] = "-a"; cmd[2] = "-l"; cmd[3] = NULL; if (execve(path, cmd, environ) < 0) perror(NULL); printf("if fail, this will be printed\n"); }
C
복사
execve는 본 함수를 호출하는 프로세스를 path에 해당하는 파일을 실행하는 새 프로세스로 바꾼다.
첫번째 인자는 실행할 파일의 경로이며, 두번째 인자는 옵션을 담는 문자열의 배열이다. (문자열도, 이중포인터도 null terminate 되어있어야한다). cmd[0]에 해당하는 문자열은 관습적으로 실행하는 프로그램의 이름을 쓰지만 위와 같이 해도 실행은 된다... 위의 경우 “/bin/ls -a -l”이 실행되게 된다.
세번째 인자는 환경변수이다.
execve는 성공할 경우 아예 반환값이 없고 실패할 경우에만 -1을 반환한다.
As the execve() function overlays the current process image with a new process image, the successful call has no process to return to. If execve() does return to the calling process, an error has occured;