[42 Seoul] pipex - 회고록

현톨·2022년 11월 11일
0

42 서울 기록하기

목록 보기
6/8

사전 지식

envp: main() 함수 중 프로그램 환경 변수 값을 담고있는 인수이다.

사용 예시

int main( int argc, char **argv, char **envp)
{
   while( *envp)
      printf( "%s\n", *envp++);

   return 0;
}

출력 결과
다음과 같이 환경변수 목록이 출력됨을 확인할 수 있다.


unlink: 파일을 삭제하는 시스템 콜 함수로, 하드링크의 이름을 삭제하고, 하드 링크가 참조하는 count를 1 감소시킨다. rm 명령어 처리할 때 써야하는 것 같다.

사용 예시

int	main(int argc, char **argv)
{
	unlink(argv[1]);
	return (0);
}

execve:
int execve(const char filename, char const argv[], char *const envp[])
첫번째 매개변수로 받은 파일명을 실행시킨다. 이 때 두번째 인자로 옵션을 추가할 수 있다. 환경변수는 어디에 쓰이는건지 잘 모르겠다..
사용 예시

int	main(int argc, char **argv, char **envp)
{
	execve("/bin/ls", argv, envp);;
	return (0);
}

dup2:
int dup2(int fildes, int fildes2)
첫번째 매개변수로 받은 파일디스크립터를 두번째 매개변수의 파일디스크립터로 복제한다. fildes2가 0이면 fildes의 내용을 표준 입력으로 받겠다는 의미이다.


pipe:
int pipe(int fd[2])
하나의 파이프 및 파이프에 대한 두개의 파일 디스크립터를 생성한다.
fd[0] : 데이터를 입력받는 파일 디스크립터이다.
fd[1] : 데이터를 출력할 수 있는 파일 디스크립터이다.

사용 예시

int	main(int argc, char *argv[], char *envp[])
{
	int	pid;
	int	fd1;
	int	fd[2];
    // 보기 편하라고 정적할당으로 적었지만 실제로는 동적 할당으로 해야하는 것 같다.
	const char	*grep[3] = {"/usr/bin/grep", "a", 0};
	const char	*wc[3] = {"/usr/bin/wc", "-w", 0};
	int	pipe1;
	int	status;

	// infile을 열어 fd1에 저장한다.
    fd1 = open("./infile", O_RDONLY);
	// 파이프라인을 생성한다.
    pipe1 = pipe(fd);
	// 표준 입력으로 infiile의 내용을 받는다.
    dup2(fd1, 0);
	close(fd1);
    // 프로세스를 복제한다. (자식 프로세스가 먼저 실행됨)
	pid = fork();
	if (pid > 0) // 부모 프로세스
	{
    	// 파이프에서 출력된 내용을 표준 입력으로 읽는다.
		dup2(fd[0], 0);
		close(fd[1]);
		close(fd[0]);
        // 자식 프로세스가 종료될 때 까지 대기한다.
		waitpid(pid, &status, 0);
        // 읽어낸 표준 입력의 길이를 카운트한다.
		execve(wc[0], wc, envp);
	}
	else // 자식 프로세스
	{
    	// 파이프에 표준 출력된 내용을 작성한다.
		dup2(fd[1], 1);
		close(fd[0]);
		close(fd[1]);
        // 표준 입력으로 받은 infile 내용에서 a를 찾는다.
		execve(grep[0], grep, envp);
	}
}

문자열 파싱

  1. 첫번째 매개변수는 infile이어야 하기 때문에 open 함수를 통해 argv[1]의 파일 디스크립터를 저장한다.
  2. 마지막 매개 변수는 outfile이어야 하기 때문에 마찬가지로 open함수를 통해 파일 디스크립터를 저장한다.
  3. 첫번째와 마지막 사이의 매개변수는 명령어들의 집합이다. 보너스도 할 것을 염두에 두었기 때문에 각각의 명령어들을 이중포인터 안에 저장했다.
char	**get_cmds(int argc, char **argv)
{
	char	**cmds;
	int		i;
	int		j;

	i = -1;
	cmds = (char **)malloc(sizeof(char *) * (argc - 1));
	if (!cmds)
		return (0);
	while (++i + 2 < argc - 1)
	{
		j = 1;
		cmds[i] = (char *)malloc(sizeof(char) * (ft_strlen(argv[i + 2]) + 2));
		if (!cmds[i])
			return (0);
		cmds[i][0] = '/';
		while (*argv[i + 2])
			cmds[i][j++] = *argv[i + 2]++;
		cmds[i][j] = 0;
	}
	cmds[i] = 0;
	return (cmds);
}

리다이렉션

  1. 파이프를 열고, 자식프로세스를 생성한다.
  2. 자식 프로세스에서는 명령어를 실행시키고 그 출력을 파이프의 입구에 작성한다.
  3. 부모 프로세스는 파이프의 출구를 열고 자식프로세스를 기다렸다가 그것을 표준입력으로 받는다.
  4. 만약 첫번째 명령어라면 입력파일을 읽어내어 그것에 대한 명령어를 실행시키고, 마지막 명령어라면 명령어의 출력을 파이프의 입구가 아닌 출력파일에 작성한다.
  5. 명령어의 갯수만큼 반복한다.
profile
기록하는 습관 들이기

0개의 댓글