on
[42SEOUL] pipex : 사전 학습
[42SEOUL] pipex : 사전 학습
이미 잘 알고 있는 UNIX 매커니즘을 더 자세히 알아가는 프로젝트
Redirection : [<] [>]
입출력의 방향을 바꾸는 명령어
유닉스 프로그램은 기본적으로 표준 입력 (stdin), 표준 출력 (stdout) 채널을 갖고 있음. → 프로그램을 사용할 때 사용자가 터미널에 직접 정보를 입력하는 채널이 표준 입력이며, 실행 결과 등이 터미널에 출력되는 채널이 표준 출력임.
(백그라운드에서 실행되는 데몬 같은 경우 제외) 대부분의 유닉스 프로세스는 실행될 때 표준 입출력에 대한 파일 서술자(file descriptor, fd)를 할당함. 각각 0과 1이며, unistd.h 에 STDIN_FILENO , STDOUT_FILENO 매크로로 정의되어 있음.
0 표준입력 (stdin [keyboard]) 1 표준출력 (stdout [screen]) 2 표준에러 (stderr [screen])
표준 입출력과 입력 파일, 출력 파일이 모두 고유의 파일 서술자를 갖고 있다는 점을 생각해보면, 이는 각 fd 사이의 데이터 흐름의 방향을 변경/지정해주는 기능이라고 할 수 있음.
사용법
< : 지정된 파일의 내용을 표준 입력으로 넘겨줌.
> : 위와 반대로 표준 출력에 전달된 내용을 지정된 파일로 넘겨줌. → 기존 파일이 있을 경우 덮어쓰여짐.
>> : 표준 출력에 전달된 내용을 지정된 파일의 내용에 추가함.
예제
입력 리다이렉션
표준 입력에 내용을 모두 입력하고 나면 ctrl + d 를 입력해 프로세스에 EOF 를 전달해야 함.
~/user $ < file.txt A B C ~/user $ 0< file.txt A B C
출력 리다이렉션
~/user $ hello > file.txt ~/user $ cat file.txt hello ~/user $ echo "hihi Linux" >> file.txt ~/user $ cat file.txt hello hihi Linux ~/user $ echo bye > file.txt ~/user $ cat file.txt bye
에러 출력 리다이렉션
보통 출력을 보고 싶지 않을 때 /dev/null 로 많이 보냄. → 주기적으로 비워지는 공간, 휴지통이라 생각하면 쉬움.
~/user $ fifle bash: fifle: command not found ~/user $ fifle 2> file.txt ~/user $ cat file.txt bash: fifle: command not found
Pipe : [ | ]
여러 프로그램을 묶어주는 명령어
여러개의 명령어를 실행할 때 이전 명령어의 결과를 다음 명령어의 입력값으로 사용하고 싶을 때가 있음. 명령어의 입력 - 실행 - 결과 과정을 파이프 안에 흐르는 액체로 비유한다면, 첫 번째 명령어의 파이프 결과를 화면 출력 대신 다른 명령어 파이프로 흘러가도록 연결한다고 생각하면 됨.
한 번에 사용 가능한 파이프의 개수는 제한이 없음.
이전 명령어의 출력값을 필터링하거나 가공할 때 주로 사용하기 때문에 awk cut grep more 등의 명령어들을 조합해서 많이 사용함.
사용법 / 예제
text.txt 파일에서 abc 라는 글자가 포함된 라인만 출력
~/user $ cat test.txt | grep abc abc abcdef abcd
현재 디렉토리에서 c 라는 글자가 들어간 파일 중 java 가 들어간 파일을 제외하고 출력
~/user $ ls | grep c | grep -v java language.c language.cpp
실행 중인 프로세스 목록에서 bash 프로세스 목록을 출력
~/user $ ps -ef | grep bash root 1293 284 0 Apr18 tty1 00:00:00 -bash
Shell
프로세스를 시작시키는 것이 셀의 주요 기능이며, UNIX 에서 프로세스를 시작하는 방법은 Init fork() 2가지 뿐임.
대부분의 프로그램은 Init 이 아니기 때문에 프로세스를 시작하는 실질적인 방법은 fork() syscall 뿐이라 볼 수 있음.
fork
#include int fork();
fork() 를 호출하는 프로세스는 부모 프로세스가 되며, 이 기능을 호출하면 운영 체제가 부모 프로세스로부터 자식 프로세스를 복제하여 두 프로세스를 병렬로 실행함. 기존 프로세스는 두 개의 분리된 프로세스로 분기됨. 그런 다음 자식 프로세스는 exec() 을 사용하여 자신을 새 프로그램으로 바꿈. 부모 프로세스는 다른 작업을 수행할 수 있으며, wait() 을 사용하여 자식 프로세스를 계속 감시할 수 있음.
모든 프로세스는 생성될 때 프로세스 아이디를 부여받음. → fork() 함수는 부모에게는 자식 프로세스의 pid ( pid_t 정수형) 를 반환하고, 자식에게는 0을 반환함. 이를 이용하여 자식 프로세스에게 특정 명령을 시킬 수 있음.
pipe
#include pipe();
두 프로세스가 생산자-소비자 모델에 따라 통신할 수 있게 해주는 원형 버퍼임. 즉, 한 프로세스가 쓰고 다른 프로세스가 읽는 선입선출 형태의 큐라 할 수 있음.
자식 프로세스는 생성 시점에 부모 프로세스가 사용중인 메모리 영역을 복사해오지만, 그 이후로는 두 프로세스 간에 직접 정보를 교환하는 것이 불가능함. 이 때 프로세스 간 정보 교환 채널이 되어주는 것이 파이프임.
파이프에는 일정한 크기의 공간이 할당되어 있으며, 단방향 데이터 전송 기능을 수행함. 인자로 전달된 배열에는 파이프의 양 끝단을 가리키는 파일 디스크립터가 입력됨. pipefd[0] 과 pipefd[1] 에 입력된 파일 디스크립터가 각각 파이프의 읽기와 쓰기를 위한 채널임.
waitpid
pid_t waitpid(pid_t pid, int *stat_loc, int options);
fork() 함수로 자식 프로세스를 생성하면 부모 프로세스와 자식 프로세스는 순서에 관계 없이 실행되고, 먼저 실행을 마친 프로세스는 종료됨.
이 때 좀비 프로세스 같은 불안정 상태의 프로세스가 발생하는데 이를 방지하려면 프로세스 동기화 함수를 수행해서 부모 프로세스와 자식 프로세스를 동기화 시켜야 함.
동기화 후에 자식 프로세스는 if (pid == 0) 일 경우 구문을 수행한 뒤 종료하며, 부모 프로세스의 경우 wait() 를 통해 자식 프로세스가 종료된 뒤 나머지 구문을 수행하고 종료함.
WIFEXITED
WIFEXITED(status);
exit() 를 호출하기 위한 인자나 return 값이 설정되고 종료된 자식 반환 코드의 최하위 8비트를 평가함.
자식 프로세스가 정상적으로 종료 되었다면 0 을 반환함.
execve
#include int execve(const char *path, char *const argv[], char *const envp[]);
path 가 가리키는 파일을 실행함.
매개변수 const char *path : 실행 파일의 디렉토리 포함 전체 파일의 명 char *const argv[] : 인수 목록
반환값 성공 시, 0 반환 실패 시, -1 반환
open
#include int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
이미 존재하는 파일을 열거나 새로운 파일을 생성하는 함수임.
정상적으로 열렸으면 0 , 오류가 발생했다면 -1 을 반환함.
flags 옵션 O_RDONLY : 읽기 전용으로 오픈함. O_RDWR : 파일 읽고 쓰기 모두 가능하게 함. O_CREAT : 파일이 존재하지 않으면 새로 생성함. O_TRUNC : O_WRONLY 또는 O_RDWR 로 열 때, 이미 존재하는 파일이면 파일 내용을 삭제하여 파일 크기를 0으로 만듬.
mode 옵션 → 파일에 대한 access 권한을 설정함. chmod 설정을 해준다고 보면 됨.
close
open 으로 열린 파일을 닫음.
dup2
#include int dup2(int fd, int fd2);
fd 의 값을 fd2 로 지정해서 복제하는 함수로, fd2 가 이미 열려있으면 fd2 를 닫은 후 복제가 됨.
성공 시 새 파일 디스크립터를 반환하고, 실패 시 -1 을 반환함.
perror
오류 메시지를 strerr 로 출력함.
exit
프로그램을 종료하는 함수임.
exit(0) 은 정상 종료, exit(1) 은 에러 메시지 종료를 뜻함.
from http://leejiwonn.tistory.com/12 by ccl(A) rewrite - 2021-11-09 20:02:05