2021/일일 기록

2021 06 07(월)

ililillllllliilli 2021. 6. 8. 14:49

1. 학습 날짜 : 20210607(월)


2. 학습 시간 : 12:00 ~


3. 학습 주제 : pipex 자료조사, 구현방법의 생각


4. 동료 학습 방법 : 동료 1명


5. 학습 목표 :

  • pipex 자료조사

  • Redirection 설명할 수 있을 때 까지 자료조사, 이해
  • Pipe 설명할 수 있을 때 까지 자료조사, 이해

  • pipex 구현 방법 생각해보고, Design 해보기 - main 문 중심 Design

6. 학습 내용 :


Redirection - file descriptor 메타문자의 정의

https://www.guru99.com/linux-redirection.html

Redirection is a feature in Linux such that when executing a command, you can change the standard input/output devices. The basic workflow of any Linux command is that it takes an input and give an output.

이 세 개의 표준 스트림은 사용자의 터미널에 부착된다.



3< input.txt, 4> output.txt 에 관해


3< input.txt:

< input.txt 는 상당히 익숙한데 비해 3 < input.txt는 익숙치 않다.

3< input.txt 는 어떤 의미를 가질까?


만약, 원래 3번 파일로부터의 입력을 받는 프로그램이 존재한다면 -프로그램x 로 정의, input.txt 로부터의 입력을 받도록 redirection시켜준다.

예) 프로그램x가 표준입력이 아닌 3번 파일로부터의 입력을 받는 프로그램이라면, 3번 파일을 읽지 않고, input.txt라는 파일로 입력을 준다.


프로그램x 3< input.txt 그림 :

Screen-Shot-2021-06-07-at-2-13-19-PM

4> output.txt :

만약, 원래 어떤 프로그램x가 4번 파일(fd==4)에 출력작업을 한다고 가정하고, 그런 프로그램 x가 존재한다고 했을 때, 4> output.txt 는 fd==4가 아닌 output.txt 에 데이터출력작업을 행한다.



표준입력과 표준출력에 대해

https://www.guru99.com/linux-redirection.html

Whenever you execute a program/command at the terminal, 3 files are always open, viz., standard input, standard output, standard error.


stdin : 별도의 리다이렉션 없이 프로그램을 시작한 경우, 표준 입력 스트림은 키보드에서 받아온다.

표준 입력(Standard input)은 프로그램에 입력되는 데이터의 표준적인 출처(장비나 파일)를 일컬으며 *stdin* 으로 줄여 표현한다.


stdout : 리다이렉션 없이 표준 출력은 프로그램을 시작한 텍스트 터미널이 된다.

표준 출력(Standard output)은 프로그램에서 출력되는 데이터의 표준적인 방향(장비나 파일)을 일컬으며 크게 표준 출력(*stdout*)과 표준 에러(*stderr*)로 구분할 수 있다.


어떤 프로그램에 있어 만약 대부분의 입력과 출력이 한 출처로부터만 발생한다면 사용자가 명시하지 않는 이상 기본적으로 사용할 입력과 출력을 프로그램 개발 시에 지정할 수 있으면 좋을 것이다. 이렇게 한 프로그램이 기본적으로 사용할 입출력 대상을 ‘표준 입출력’이라고 한다.

우리의 예제 프로그램 ‘쉘’은 키보드 입력을 표준 입력으로 하고 모니터 콘솔 출력을 표준 출력으로 한다.


표준 입출력은 사용자가 다른 입출력 매체를 지정하지 않았을 때의 기본 입출력 매체라고 이야기했다



pipe(int fd[2]) 의 순서에 대해

왜 fd[0]이 읽는 stream, fd[1]이 쓰는 stream일까?

https://architectophile.tistory.com/9?category=880956

그리고 여기에서 알아야 할 매우 중요한 개념이 있는데, 나는 이것을 이해하기 위해 위의 다이어그램들을 그려보며 생각해야 했다. 내가 처음에 얘기했던 것처럼 위의 다이어그램들은 데이터가 왼쪽에서 오른쪽으로 흐르는 모델이라는 것을 잘 생각해보자. 파일 디스크립터는 배열 안에서 설정되어 4에 쓰여진 데이터가 3에서 읽히도록 된다. 하지만 당신은 왜 4가 왼쪽으로 가고 3이 오른쪽으로 가는지 궁금해할 수 있다.
여기서 핵심적인 내용은 바로 pipe() 호출에 의해 설정되는 읽기(read), 쓰기(write) 액션은 바로 파이프를 사용하는 양쪽의 2개의 프로세스들의 관점에서 정의된다는 것이다. 따라서 pipe() 호출에 4를 writable end로 설정하면\, 그것은 첫 번째 명령(sort)의 프로세스가 출력(output)을 쓰기(write)하는\ 파이프의 입력(input)을 전달받는 파이프의 왼쪽 파일 디스크립터가 되는 것이다. 반대로 pipe() 호출에 3을 readable end로 설정하면\, 그것은 두 번째 명령(grep)의 프로세스가 입력(input)을 읽기(read)하는\ 파이프의 출력(output)을 전달하는 파이프의 오른쪽 파일 디스크립터가 되는 것이다.


해석 : 양쪽 2개의 프로세스의 관점에서 정의된다는 것 == sort | wc 일 때, 파이프는 sort에서 데이터를 읽어들인 후에 wc에 데이터를 write 해야하기 때문에 int fd[2] 의 순서가 fd[0] == read , fd[1] == write의 순서로 저장된다.



dup()와 dup2

dup() : 먼저 dup 함수는 입력 인자로 열려진 파일 디스크립터를 전달하면 같은 물리적 파일을 연 새로운 파일 디스크립터를 반환합니다. 이와 같이 열면 두 개의 파일 디스크립터는 커널의 같은 파일 테이블 엔트리를 참조합니다


dup2() : dup2 함수는 첫 번째 인자로 열려진 파일 디스크립터를 전달하고 두 번째 인자로 파일 디스크립터를 전달하면 첫 번째 인자로 열려진 파일 디스크립터가 참조하는 파일 테이블 엔트리를 두 번째 전달한 파일 디스크립터도 참조합니다. 만약 두 번째 인자로 전달한 파일 디스크립터가 열려진 파일 디스크립터일 때는 먼저 닫고 난 후에 복제합니다.


  • dup() 와 dup2()의 차이 :
    • dup() : 새로운 fd를 만들어 fd 테이블을 연결
    • dup2(): fd를 지정하여 새로 참조시킬 수 있고, 기존에 열려있는 fd를 지정하여 연결을 끊게 한 뒤 새롭게 참조시킬 수 있음.



shell command 위치


Shell command 위치가 다르기 때문에 추후 프로그램 작성시 execv() 사용에 문제가 있을 것으로 판단.


  ~ % which touch
/usr/bin/touch

  ~ % which wc
/usr/bin/wc

  ~ % which mkdir
/bin/mkdir

  ~ % which cp
/bin/cp

  ~ % which pwd
pwd: shell built-in command

  ~ % which ps
/bin/ps

  ~ % which bash
/bin/bash

  ~ % which zsh
/bin/zsh

External, Internal Command :

https://www.geeksforgeeks.org/internal-and-external-commands-in-linux/

  • Internal Commands : Commands which are built into the shell. For all the shell built-in commands, execution of the same is fast in the sense that the shell doesn’t have to search the given path for them in the PATH variable, and also no process needs to be spawned for executing it.
    Examples: source, cd, fg, etc.
  • External Commands : Commands which aren’t built into the shell. When an external command has to be executed, the shell looks for its path given in the PATH variable, and also a new process has to be spawned and the command gets executed. They are usually located in /bin or /usr/bin. For example, when you execute the “cat” command, which usually is at /usr/bin, the executable /usr/bin/cat gets executed.
    Examples: ls, cat etc.
  ~ % which pwd
pwd: shell built-in command

pwd 는 shell 의 내부적으로 구현된 command / 툴이다.

물론, 시스템 명령어 상 존재하기도 한다.

 ~ % which /bin/pwd
/bin/pwd

Internal Command 의 경우, 명령어가 파일로 존재하지 않는다

External Command의 경우, 파일은 /bin 또는 /usr/bin 에 존재한다.


웬만한 external command들은 아래 디렉토리에 존재한다고 한다.

"/bin/"
"/usr/local/bin/",
"/usr/bin/", 
"/usr/sbin/",
"/sbin/",



const char *char * const의 차이. :

The difference is that const char * is a pointer to a const char, while char * const is a constant pointer to a char.

The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).


const char * : const가 char 를 수식.

char * const : const가 ptr를 수식.

Screen-Shot-2021-06-07-at-8-22-26-PM



FILE TREE


📦pipex
 ┣ 📂includes
 ┃ ┗ 📜pipex.h
 ┣ 📂libft
 ┣ 📂srcs
 ┃ ┣ 📜initiate.c
 ┃ ┣ 📜main.c
 ┃ ┣ 📜redirection.c
 ┃ ┗ 📜utils.c
 ┣ 📜.gitignore
 ┣ 📜Makefile
 ┗ 📜README.md



pipex.c의 대략적인 흐름

int        main(int argc, char **argv)
{
    pid_t        pid;
    t_parsed    *parsed[2];
    int            execv_error[2];
    int            status;

        /*******************
      1. agrument가 5개가 아니면?
      2. parsing 구조체 초기화
      3. parse 진행
      4. file path가 valid한가?
      5. command가 valid한가?
        ********************/
    if (!(argc == 5 && init_parsed(parsed) && \
            parse_argument_vector(argv, parsed) && is_valid_path(parsed)) && \
                is_valid_cmd(parsed))
        exit(0);
    pid = fork();        //프로세스 분기
    if (pid == -1)
        return (0);

  // child process.
  if (pid == 0)
    {
        if (!(redirect_in() && connect_pipe()))        // input redirection, pipe연결.
            exit(1);
        if (run_cmd(parsed, CHILD_INDEX) == -1)
            exit(1);
    }

  //parent process.
    waitpid(pid, &status, 0);
    if (WIFEXITED(status))            //비정상 종료시 리소스 환원
        exit(0);
    if (!(redirect_out() && connect_pipe()))    // output redirection, pipe연결.
        exit(1);
    if (run_cmd(parsed, PARENT_INDEX) == -1)
        exit(1);
}





학습에 도움된 사이트 :

    비고
표준입력-표준출력 위키피디아 https://ko.wikipedia.org/wiki/%ED%91%9C%EC%A4%80_%EC%8A%A4%ED%8A%B8%EB%A6%BC  
표준입력-표준출력 블로그 https://shoark7.github.io/programming/knowledge/what-is-standard-stream  
dup, dup2() https://reakwon.tistory.com/104  
wait, waitpid() https://codetravel.tistory.com/30  
Shell Command 위치 https://askubuntu.com/questions/594467/where-are-all-the-terminal-commands-stored-and-how-to-view-them

https://www.linuxquestions.org/questions/linux-newbie-8/where-are-my-commands-stored-674176/
 
internal command, external command https://www.geeksforgeeks.org/internal-and-external-commands-in-linux/  
     
     
     

오늘 발견한 문제와 해결방안:

  • 발견한 문제와 해결방안이 딱히 존재하지 않았다.



7. 학습 총평 :

  • 좋았다.
  • 단지, 과제를 하는 시간동안은 오로지 과제에 집중해야만 하는 것이 아쉽다.
  • 중간에 다른 공부도 껴넣었으면 한다.



8. 다음 학습 계획 :

  • ​ pipex 마무리
  • pipex 개념 정리 마지막