pipex

과제 분석

mandatory

./pipex file1 cmd1 cmd2 file2

실행 결과가

< file1 cmd1 | cmd2 file2

와 같은 결과가 나와야 한다.

file1을 읽어서 cmd1 을 실행하고 그 결과를 cmd2의 입력으로 준다.
cmd2를 실행한 결과를 file2에 출력한다.

보너스

  1. 다중 cmd

    ./pipex file1 cmd1 cdm2 cmd3 cmd4 ... cmdn file2

의 결과는

< file1 cmd1 | cmd2 | cmd3 | cmd .... | cmdn file2

와 같아진다.
여기서 알 수 있는게 맨 첫 매개변수는 읽어들일 파일이고 argv[2] ~ argv[argc - 2]까지는 실행할 명령어다. 그리고 마지막 argv[argc - 1]이 결과를 출력할 파일 이름이다.

  1. '>>', '<<' 처리

./pipex here_doc LIMITER cmd cmd1 file

cmd << LIMITER | cmd1 >> file

표준 입력을 통해 LIMITER가 나오기 전까지 읽어들이고, 읽은 값에 cmd 적용. 결과에 다시 cmd1 적용 후 file에 출력하다.

최종 결과 모습

./pipex file1 cmd1 cmd2 fil2

이런식으로 프로그램을 실행시키면 다음의 실행 결과와 같은 결과를 만들어야 한다.

< file1 cmd1 | cmd2 > file2

file1을 input으로 읽어서 cmd1 실행. 이 결과를 cmd2의 입력으로 cmd2를 실행시키고 file2에 결과를 출력하라는 뜻이다.

예시

file1의 내용이
a
b
c
d
abc
hello
aba

일 때,

< infile grep a | wc -l > outfile

실행 시, "3" 출력

redirection

'<' : 입력 redirection

정확히는 "[n] < word" 의 꼴로 사용한다.
n 은 redirect할 파일 디스크립터가 되고 word에는 읽을 파일 이름이 된다. n을 명시하지 않으면 기본 0 이 들어간다.

'>' : 출력 redirection

[n]>[|]word 의 꼴로 사용한다.
n 파일 디스크립터로 write을 목적으로 word 파일을 오픈 후 결과를 출력.
noclobber 옵션이 활성된 경우, redirection이 불가능하다.

https://www.gnu.org/software/bash/manual/html_node/Redirections.html
https://howto.lintel.in/protect-files-overwriting-noclobber-bash/#:~:text=The%20noclobber%20option%20prevents%20you,and%20is%20a%20regular%20file.

'>>' : 출력 확장 redirection

[n]>>word
word를 append 방식으로 열고 파일디스크립터 n으로부터 출력받는다. word가 존재하지 않는 경우 새로 만든다.

'<<' :

[n]<<[-]word
        here-document
delimiter

함수 정리

access

#include <unistd.h>
int access(const char *pathname, int mode);

설명

실제 사용자의 파일 접근 권한을 확인한다.

호출하는 프로세스가 pathname 에 접근할 수 있는지 확인한다. pathname 이 심볼릭 링크인 경우 역참조된다.

모드

모드는 수행 할 접근성 검사를 지정하며 F_OK 값이거나 R_OK, W_OK 및 X_OK 중 하나 이상의 비트 단위 OR로 구성된 마스크입니다.
저 4개를 이용해서 비트 단위 OR로 구성된 mode를 주면 되는데, 사용자가 확인하고 싶은 mode를 매개변수로 넘겨주면 된다.

예) 읽기, 실행이 가능한지 확인하고 싶으면
access(filpath, R_OK | X_OK) 이런식으로 사용.
F_OK : 파일의 존재 여부 확인
R_OK, W_OK, X_OK : 파일이 있는지 여부를 테스트하고 각각 읽기, 쓰기, 실행 권한을 가지는지 확인한다.

#include <unistd.h>
#include <stdio.h>

int		main(void)
{
    printf("**** F_OK ***\n");
    printf("F_OK not existing file : %d\n", access("not_access_test.txt", F_OK));
    printf("F_OK existing file : %d\n", access("access_test.txt", F_OK));

    printf("**** R_OK, W_OK, X_OK ***\n");
    printf("test file which user doesn't have any right\n");
    printf("R_OK %d\n", access("access_test.txt", R_OK));
    printf("W_OK %d\n", access("access_test.txt", W_OK));
    printf("X_OK %d\n", access("access_test.txt", X_OK));
}

반환 값

성공 시 0 반환.
에러 발생 시 -1이 반환되고 errno가 설정된다.

execve

int execve(const char filename, char const argv[],char *const envp[]);

argv is an array of argument strings passed to the new program. By convention, the first of these strings should contain the filename associated with the file being executed.

이게 진짜 헷갈렸다.
execve의 첫 매개변수로 실행 파일을 이름을 주는데 argv[0]에 굳이 또 이름이 왜 필요한가 했는데 관례상 적어준다. 그래서 argv의 첫 매개변수에 이상한 값을 줘도 filename을 실행하는데 아무 영향이 없다.

https://stackoverflow.com/questions/59040362/confusion-about-execve-parameters

명령어 실행 파일 위치 찾기

hmm.... 일단 나는 which 명령어를 썼다.
which 말고 whereis 명령어도 사용하려면 할 수 있다.
But!! whereis를 사용하면 사용자 PATH에 대해서는 검색을 못한다. 무슨 말이냐면 시스템에서 기본으로 설정된 몇몇 경로들을 제외하고는 실행파일을 찾지 않는다는 말이다.
반면에 which는 사용자 정의 PATH도 검색한다.

예시)

예를 들어 norminette의 실행 파일 위치는 "/usr/local/bin/norminette"다. 이 위치는 사용자가 PATH에 등록을 해주면 쉘에 norminette를 입력해서 사용할 수 있다. which를 사용하면 norminette의 실행파일 위치를 얻을 수 있지만 whereis를 사용하면 찾을 수 없다.

이 방법말고 함수에서 char *envs[] 에서 strstr() 함수를 써서 PATH를 split()해서 경로를 얻을 수 있다고 한다.

Mandatory

간단하게 어떤 순서로 작동되야 되는지 그려봤다.
실행할 명령어가 2개로 고정됐기 때문에 순서대로 명령어를 실행하는 식으로 구현했다.

위 과정을 좀 더 자세히 그린게 아래 그림이다.

좋은 웹페이지 즐겨찾기