셸에서 사용하는 파이프(|)와 리다이렉션(>, <, 2>) 은 일반적인 시스템 콜이나 바이너리 실행의 일부가 아니라, 셸이 제공하는 특별한 문법(syntax)이다. 운영체제 커널은 이런 문법을 직접적으로 이해하지 못하며, 오직 셸만이 이를 처리할 수 있다.때문에 파이프와 리다이렉션을 포함한 명령어는 반드시 셸 프로세스를 거쳐 실행된다.
파이프(Pipe) 동작의 원리
예를 들어 다음 명령을 보자. 셸은 이를 다음 단계로 처리한다.
ls -al | grep ".txt"
1. 자식 프로세스 생성 (fork)
부모 셸은 우선 하나의 자식 프로세스를 생성한다. 이 자식 프로세스는 exec를 통해 셸 프로세스(/bin/sh)로 변경된다.
2. 자식 셸 프로세스에서 다시 두 개의 프로세스 생성 (fork)
자식 셸이 다시 두 개의 프로세스를 만든다. 하나는 ls -al 명령을, 다른 하나는 grep ".txt" 명령을 실행하기 위한 프로세스다.
3. 자식 셸 프로세스에서 파이프 생성 (pipe syscall)
셸은 시스템 콜 pipe()를 호출하여 두 프로세스를 연결할 익명 파이프를 만든다. 커널은 두 개의 파일 디스크립터(FD)를 반환한다.
int fd[2];
pipe(fd); // fd[0]: read, fd[1]: write
4. 파일 디스크립터 연결 (dup2 syscall)
ls -al 프로세스의 표준 출력을 파이프의 쓰기 FD에 연결한다.
grep ".txt" 프로세스의 표준 입력을 파이프의 읽기 FD에 연결
// ls 프로세스 입장
dup2(fd[1], STDOUT_FILENO); // 표준 출력을 파이프 쓰기 FD에 연결
close(fd[0]); // 불필요한 FD 닫기
// grep 프로세스 입장
dup2(fd[0], STDIN_FILENO); // 표준 입력을 파이프 읽기 FD에 연결
close(fd[1]); // 불필요한 FD 닫기
5. 명령어 실행 (exec syscall)
각 프로세스는 이제 실제 명령어를 실행한다. 이때 데이터는 파이프를 통해 흐르게 된다.
리다이렉션(Redirection)의 원리
리다이렉션은 파이프와 유사하지만 더 단순한 구조를 가진다.
echo "hello world" > output.txt
1. 셸 프로세스 생성 (fork → exec)
부모 셸이 자식 프로세스를 생성하고, 자식 프로세스는 다시 셸(/bin/sh)이 된다.
2. 자식 셸이 파일 열기 (open syscall)
리다이렉션 대상인 파일을 연다.
int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
3. 파일 디스크립터 연결 (dup2 syscall)
표준 출력을 파일에 연결한다.
dup2(fd, STDOUT_FILENO); // 자식 프로세스의 stdout → output.txt
close(fd);
4. 명령어 실행 (exec syscall)
이제 셸은 echo 명령을 실행하고, 명령의 출력은 파일로 저장된다.
최종 프로세스 계층 구조
결국 프로세스 계층 구조는 아래와 같다.
부모 셸
└─ 자식 셸 (파이프/리다이렉션 처리)
├─ 프로세스1 (예: ls)
└─ 프로세스2 (예: grep)
'CS > Linux' 카테고리의 다른 글
| [Linux] systemd 기반 시스템 운영에 필요한 필수 명령어 (1) | 2025.07.27 |
|---|---|
| [Linux] 데몬의 실행 방식 (3) | 2025.07.25 |
| [Linux] 마운트 개념 `df -h` 으로 이해하기 (0) | 2024.12.11 |
| [Linux] NAT를 설정하는 방법 (0) | 2024.10.05 |
| [Linux] Firewalld vs Iptables (0) | 2024.10.05 |