Linux/Linux_programing

Shell - Redirect 구현하기

sosal 2019. 12. 23. 13:39
반응형

아는 후배, Linux 과제 도와주다가..

redirect 관련 썼던 게시물이 없어서 한번 정리해서 올려본다.

 

1. Output redirection

 

Output redirection은, 프로그램 결과를 특정 file descriptor에 write 하는것이다.

예를 들면,

 

$ ls -al > tmp.txt

위와 같은 linux shell command는, ls -al의 결과를 tmp.txt라는 파일을 생성하여 write한다. (덮어쓰기)

 

$ ls -al >> tmp.txt

위 command는 tmp.txt에 overwite 하지 않고, append (이어쓰기) 하는것이다.

 

위 command를 예제로 Output redirection 구현을 설명하자면,

1. 자식프로세스를 생성

2. 자식프로세스 안에서 tmp.txt란 파일을 생성하여, file descriptor를 가져옴.

3. output descriptor (standard output, 원래라면 출력)를 tmp.txt의 file descriptor로 바꿔줌

 => 즉 모든 출력 결과가 tmp.txt에 쓰여짐

4. exec로 자식프로세스는 ls -al을 실행 후 사라짐

 => 자식프로세스의 exec(ls -al) 의 결과가 tmp.txt로 쓰여짐

5. 부모 프로세스는 자식프로세스의 결과를 기다리고, 끝.

# process를 하나 생성한다. (Parent + Child)
# ls -al > tmp.txt

#자식프로세스 생성
pid1 = fork();
if (pid1 == 0) {  /* child */

	#tmp.txt에 해당되는 file descriptor (fd) 생성
    # O_CREAT를 없애고, O_APPEND를 해주면 '>>' redirection임
    fd = open(arg[narg], O_RDWR | O_CREAT | S_IROTH, 0644);
    
    #가끔 fd를 생성할 수 없는 상황 (Permission 혹은 fd overflow 등 존재) 예외처리
    if (fd < 0) {
            perror ("error");
            exit(-1);
    }

	#Standard output을 위에서 create한 fd로 가도록 설정
    dup2(fd, STDOUT_FILENO);
    #dup2 실행 후, 자식의 모든 출력은 fd로 저장됨
    close(fd);
    
    #exec로 원하는것 실행
    arg[narg] = NULL;
    if (narg != 0){
        execvp(*arg, arg);
        fprintf(stderr, "minish : command not found\n");
        exit(127);
    }

    exit(0);
}

/* Parent: Shell */
waitpid(pid1, NULL, 0);

#부모는 자식이 끝나면 다시 원래대로..

 

Input redirection 역시 같은 manner로,

fd가 Standard output였다면, 이젠 Standard input으로 해주면 된다.

 

pid1 = fork();
if (pid1 == 0) {  /* child */
    fd = open(arg[narg], O_RDONLY);
    if (fd < 0) {
            perror ("error");
            exit(-1);
    }
    dup2(fd, STDIN_FILENO);
    close(fd);

    arg[narg] = NULL;
    if (narg != 0){
        execvp(*arg, arg);
        fprintf(stderr, "minish : command not found\n");
        exit(127);
    }
    exit(0);
}

/* Parent: Shell */
waitpid(pid1, NULL, 0);