티스토리 뷰

팀원과 함께 작성한 중간 보고서 내용입니다 :)

 


목차

 

1.   옵션 개요

 

2.   설계 내용

a.    prompt 관련

b.    삭제 관련

c.    기타

 

3.   개발자 가이드

a.    개발환경 설정

b.    테스트 환경 설정

c.    빌드/테스트 방법

 


 

1. 옵션 개요

어떤 디렉터리에서 일부 파일은 남기고 나머지만 삭제하고자 할 때가 있다. 기존 rm의 interactive 옵션을 사용하면 모든 파일에 대해 삭제 여부를 입력하는 무의미한 작업을 반복하므로 다소 소모적이다. 따라서 본 프로젝트에서는 옵션명은 한번만 입력하고 파일명과 확장자만 반복적으로 입력하여 디렉터리 내부 다수의 파일 삭제를 돕는 고급 삭제 옵션을 추가함으로써 rm 명령어를 사용하는 사용자의 편의성을 높이려 한다.

 

옵션 타입 사용법
Short option rm -rb [디렉터리명]
Long option rm -r [디렉터리명] --except-files

<표1: 새 옵션 사용법>

 

위 표는 본 프로젝트에서 제작할 옵션 이름 및 사용 방법을 보여준다. 이 명령어 옵션을 이용하면 사용자가 입력한 파일을 제외하고 해당 디렉터리 내 모든 파일들이 한번에 삭제되며, 남은 파일들은 계층 구조를 유지한 채 남아있어 파일의 구조나 용도 파악이 용이하다.

 

 

 

2. 설계 내용

a. prompt 관련

Current Working Directory가 /home/kmi0817/opensource 때 <표1> 옵션 사용법대로 새 옵션을 사용한다고 가정한다. CWD에서의 파일 구성은 아래와 같다.

 

-      /home/kmi0817/opensource/file1.txt

-      /home/kmi0817/opensource/file2.txt

-      /home/kmi0817/opensource/sub/child1.txt

-      /home/kmi0817/opensource/sub/child2.txt

-      /home/kmi0817/opensource/sub/child3.txt

 

프롬프트에서 파일 입력 시 기본적으로 상대경로로 입력한다. 이때 여느 터미널이 제공하는 ‘tab을 누르면 디렉토리명과 파일명이 자동으로 완성’되는 기능은 제공되지 않는다. 사용자가 직접 서브 디렉터리 이름과 파일명을 정확히 입력해야 한다.

           I.    Current Working Directory 상의 파일을 입력하는 경우

경로명을 입력할 필요가 없다. 파일명과 확장자만 입력하면, 현재 디렉터리와 같은 위치에 존재한다고 간주한다. 위 프로토타입 캡처 화면에서는 첫 번째와 두 번째 입력 줄이 이에 해당한다.

 

         II.    Sub Directory 상의 파일을 입력하는 경우

경로명을 입력하되 서브 디렉터리 이름부터 입력하면 된다. 위 캡처 화면에서는 3번째 입력부터 이 상황에 대한 입력이다. CWD의 sub directory인 sub상의 child1.txt 파일을 삭제에서 제외하기 위해 sub/child.txt를 입력한 것이다.

 

        III.    Sub Directory 이름이나 파일 이름을 잘못 입력하는 경우

Shell이 입력받은 이름의 디렉터리나 파일을 찾는 데 실패한다면, 해당 디렉터리/파일을 찾을 수 없다는 문구(Cannot find [입력 디렉터리/파일 이름])과 함께 다시 한번 입력(Please, enter it again.)을 받는다.

 

       IV.    삭제에서 제외할 파일 입력 멈추려는 경우

사용자가 특정 문구를 입력하기 전까지 프롬프트는 삭제에서 제외할 파일이 있냐는 질문을 반복한다. 즉, 사용자는 더 이상 입력할 파일이 없으면 “!no”를 입력하여 질문 루프에서 빠져나올 수 있으며 이와 동시에 디렉터리 삭제가 진행된다.

 

 

b. 삭제 관련

<’-b’나 ‘--except-files’ 입력 시 remove_except_files 변경>

사용자가 터미널에서 ‘-b’나 ‘--except-files’ 옵션을 입력하면 삭제 관련한 옵션을 저장하는 rm_options 구조체 변수 x의 ‘remove_except_files’를 true로 바꾼다. 해당 옵션은 이후 다른 옵션에 영향을 주지 않고 명령을 수행하기 위한 분기점에서 사용된다.

<rm.c에서 호출한 rm(file, &x) 함수>

터미널에서 옵션과 함께 입력한 “내부를 삭제할 디렉터리(이하 디렉터리A)”는 argv를 통해 char **형의 file 변수에 담아져 rm.c에서 호출한 rm(file, &x)의 인자로 전달된다.

<remove.c에 선언된 rm(file, &x) 함수 본문>

rm 함수는 remove.c에 선언되어 있으며, 넘겨받은 file과 삭제 옵션이 담긴  구조체 인스턴스 x를 활용하여 삭제를 진행한다. 이때, if-else문을 사용하여 추가된 코드가 다른 옵션과 섞이지 않도록 다음과 같이 조건을 걸어준다.

<’-b’, ‘--except-files’ 옵션에 대한 분기점>

즉, 해당 if문은 *file이 존재하고, 전달받은 x의 remove_except_files 옵션이 활성화되어 있을 경우에만 실행된다.

<remove.c에 input 기능 추가한 결과>

if문에서는 입력받은 디렉터리의 내부 파일을 순회하며 삭제하는 반복문(while)을 시작하기 앞서, 위 사진처럼 삭제에서 제외할 파일을 입력받는 과정이 진행된다. 사용자가 연속으로 입력한 제외 파일은 문자열 배열(ex. except_files)에 저장된다.

<if문 내에서 파일 삭제하는 반복문(while)>

반복문(while) 내부는 fts_read()로 파일 객체를 불러와 삭제를 반복한다. 파일 객체는 FTSENT 구조체로 정의되는데, FTSENT 내부에는 파일 이름을 나타내는 fts_name, 파일의 경로를 나타내는 fts_path, 기준 디렉터리(본문에선 디렉터리A)에서의 깊이를 나타내는 fts_level 등으로 구성되어 있다. 해당 반복문의 종료 조건은 파일 객체가 담긴 ent가 비어 있고(NULL), RM_ERROR가 발생하지 않았을 때 정상적으로 종료(break)된다. 앞서 입력받은 배열대로 파일을 삭제에서 제외시키기 위해 추가한 코드는 다음과 같다.

위 코드는 “test_directory/sub/sub1.txt” 파일을 삭제에서 제외하는 코드로, 앞서 입력받은 파일들을 삭제에서 제외하는 코드를 작성하기 위한 테스트용이다. if문을 통해 파일 객체의 ‘경로/파일명(이름+확장자)’이 담긴 fts_path와 사용자가 입력한 ‘경로/파일명’이 일치하지 않을 때만 rm_fts() 함수를 호출하여 실제 파일 삭제를 진행한다. 만약 현재 파일 객체의 fts_path와 사용자 입력 파일이 같다면 삭제를 진행하지 않고 다음 파일 객체로 넘어간다.

 

 

 

 

 

3. 개발자 가이드

a. 개발환경 설정

1)    README 파일 확인

git clone으로 GNU coreutils를 가져온 후 README 파일 확인하면 README-hacking를 참고하라는 문구가 존재.

 

2)    README-hacking: ./bootstrap

Build 과정에 필요한 다른 소스 패키지의 파일을 가져오기 위해서는 현재 워킹 디렉토리 (~/coreutils) “./bootstrap”을 입력.

$ ./bootstrap

 

<그림1: ls on /home/kmi0817/coreutils>
<그림2: ./bootstrap 결과>

<그림2: ./bootstrap 결과>

만약 위와 같이 autoconf, automake, autopoint 등 다른 패키지가 발견되지 않고, README-prereq에서 프로그램을 실행하는 데 필요한 전제조건을 만족하는 방법을 확인하라고 한다면 다음 과정을 진행한다.

 

3)    README-prereq: 필요한 도구 설치

bootstrap, configure 스크립트와 make를 사용하려면 위 도구들이 필요. 따라서 “sudo apt-get install <도구 이름>” 명령어로, 모든 도구를 설치.

*(이때 각 도구 이름은 모두 소문자로 표기하며, 도구 이름에 띄어쓰기가 있는 XZ Utils의 경우 xz-utils를 입력.)

 

도구 설치 명령어 안내
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install autopoint
sudo apt-get install bison
sudo apt-get install gettext
sudo apt-get install git
sudo apt-get install gperf
sudo apt-get install gzip
sudo apt-get install help2man
sudo apt-get install m4
sudo apt-get install make
sudo apt-get install perl
sudo apt-get install tar
sudo apt-get install texinfo
sudo apt-get install wget
sudo apt-get install xz-utils

 

4)    ./bootstrap

필요한 도구를 모두 설치한 후 다시 한 번 ~/coreutils 위치에서 “./bootstrap”을 입력.

$ ./bootstrap

 다음과 같은 화면이 뜬다면 정상적으로 실행된 것임.

 

<그림3: 필요 도구 설치 이후 ./bootstrap>

 

5)    ./configure

<그림4: ./bootstrap 실행 완료>

 “./bootstrap” 성공 후 마지막 커맨드 라인에 “./configure” 수행 안내. configure 실행 파일의 위치는 ~/coreutils.

$ ./configure

<그림5: ls after bootstrap on /home/kmi0817/coreutils>

Build에 필요한 GNUmakefile, INSTALL, configure 등 새로운 파일이 몇 가지 추가.

<그림6: ./configure>

configure 실행 중 C 컴파일러 작동 여부, make의 nested variable 지원 여부 등을 확인.

 

6)    make와 make check

./bootstrap과 ./configure를 실행 후 안내에 따라 진행.

$ make
$ make check
$ git diff

git diff에 대한 출력이 없어야 Git master와 로컬 카피본의 차이가 없는 것이므로 정상.

 

 

b. 테스트 환경 설정

1. 먼저 테스트용 디렉터리(ex. test_directory)와 내부 파일 생성

$ mkdir test_directory
$ mkdir test_directory/sub
$ touch test_directory/sub/sub1.txt          //이하 생략

2. coreutils/src/remove.c 파일의 rm() 함수에 fprintf()로 현재 선택된 디렉터리 및 파일 정보 출력하는 코드 추가

fprintf(stderr, “fts_path: %s\n”, ent->fts_path);
fprintf(stderr, “fts_name: %s\n”, ent->fts_name);
fprintf(stderr, “fts_level: %ld\n”, ent->fts_level);

 

 

c. 빌드/테스트 방법

1. coreutils 디렉터리로 이동하여 터미널 창에 “make” 입력.

$ make

2. 테스트용 디렉터리 상단으로 이동하여 테스트할 명령어와 테스트용 디렉터리명을 입력. 명령어가 실행되면 제외할 파일명을 입력. 깊이 우선 탐색(DFS)을 통해 레벨 별로 삭제되는 파일들 추적 가능.

$ ~/coreutils/src/rm -r test_directory/sub

 

 

 

 

 

3. 결과 확인.

$ ls

 

 


5월 5일부터 10일까지 프로젝트가 빠르게 진행됐어요!

솔직히 그 전까지는 1) 삭제에서 제외할 파일 입력받기 2) 입력받은 딕셔너리 내 파일 리스트를 뽑아서 삭제에서 제외된 파일을 빼곤 다 삭제하기는 어떻게 코드를 작성해야겠다고 그림이 그려졌지만, 어디에서 어떻게 옵션을 새로 추가해야 하는지 감이 안 잡혔거든요.

그런데 팀원이 remove.c를 이야기하고 함께 remove.c를 살펴보면서 가닥이 많이 잡혔습니다!

728x90