3  파일과 디렉토리 작업

이제는 어떻게 파일과 디렉토리를 살펴보는지 알게 되었지만, 우선, 어떻게 파일과 디렉토리를 생성할 수 있을까요? 바탕화면(Desktop) shell-lesson-data 디렉토리로 돌아가서 pwd 명령어로 현재 디렉토리 위치를 확인한다.

$ pwd
/Users/nelle/Desktop/shell-lesson-data

ls -F 명령어를 사용하여 무엇을 담고 있는지 살펴본다. 다음으로 exercise-data/writing 디렉토리로 이동하여 그 안에 무엇이 들어 있는지 살펴본다:

$ cd exercise-data/writing/
$ ls -F
haiku.txt  LittleWomen.txt

3.1 디렉토리 생성

명령어 mkdir thesis을 사용하여 새 디렉토리 thesis를 생성한다 (출력되는 것은 아무것도 없다.):

$ mkdir thesis

이름에서 유추를 할 수도, 하지 못할 수도 있지만, mkdir은 “make directory(디렉토리 생성하기)”를 의미한다. thesis는 상대 경로여서(즉, 앞에 슬래쉬가 없음), 새로운 디렉토리는 현재 작업 디렉토리 아래 만들어진다:

$ ls -F
haiku.txt  LittleWomen.txt  thesis/

방금 thesis 디렉토리를 만들었으므로 아직 아무것도 없다:

$ ls -F thesis

mkdir 명령어는 한번에 하나의 디렉토리를 만드는 것으로 국한되지 않는다. -p 옵션을 사용하면 mkdir 한번의 작업으로 중첩된 하위 디렉토리가 있는 디렉토리를 만들 수 있습니다:

$ mkdir -p ../project/data ../project/results

ls 명령어 -R 옵션을 추가하면 디렉토리 내에 중첩된 모든 하위 디렉토리가 나열됩니다. ls -FR을 사용하여 project 디렉토리에서 방금 만든 디렉토리 계층 구조를 재귀적으로 나열해 보겠습니다:

$ ls -FR ../project
../project/:
data/  results/

../project/data:

../project/results:
주의

동일한 작업을 수행하는 두가지 방법

쉘을 사용해서 디렉토리를 생성하는 것이나 (윈도우) 파일 탐색기를 사용하는 것과 별반 차이가 없다. 운영체제 그래픽 파일 탐색기를 사용해서 현재 디렉토리를 열게 되면, thesis 디렉토리가 마찬가지로 나타난다. 파일과 상호작용하는 두가지 다른 방식이 존재하지만, 파일과 디렉토리는 동일하다.

파일과 디렉토리를 위한 좋은 명칭

명령라인으로 작업할 때, 복잡하고 어려운 파일과 디렉토리는 삶의 질을 현격히 저하시킨다. 다음에 파일 명칭에 대한 유용한 팁이 몇 개 있다.

  1. 공백(whitespaces)을 사용하지 않는다. 공백은 이름을 의미있게 할 수도 있지만, 공백이 명령라인 인터페이스에서 인자를 구별하는데 사용되기에, 파일과 디렉토리 명에서는 피하는 것이 상책이다. 공백 대신에 - 혹은 _ 문자를 사용한 다. (예를 들어, north pacific gyre/ 대신 north-pacific-gyre/을 사용))

  2. 대쉬(-)로 명칭을 시작하지 않는다. 명령어가 -으로 시작되는 명칭을 선택옵션으로 처리하기 때문이다.

  3. 명칭에 문자, 숫자, . (마침표), - (대쉬), 그리고 _ (밑줄)을 고수한다.

명령라인 인터페이스에서 그외 다른 많은 문자는 특별한 의미를 갖는다. 일부 특수 문자가 잘못 사용되면 명령어가 기대했던 대로 동작하지 못하게 하거나, 심한 경우 데이터 유실을 야기할 수도 있다.

공백을 포함하거나 알파벳이 아닌 문자를 갖는 파일명이나 디렉토리명을 굳이 지정할 필요가 있다면, 인용부호("")로 파일명이나 디렉토리명을 감싸야 한다.

3.2 텍스트 파일 생성

cd 명령어를 사용하여 thesis로 작업 디렉토리를 변경하자. Nano 텍스트 편집기를 실행해서 draft.txt 파일을 생성하자:

$ cd thesis
$ nano draft.txt
주의

어떤 편집기가 좋을까요?

nano가 텍스트 편집기다”라고 말할 때, 정말 “텍스트”만 의미한다. 즉, 일반 문자 데이터만 작업할 수 있고, 표, 이미지, 혹은 다른 형태의 인간 친화적 미디어는 작업할 수 없다. nano를 사용하는 이유는 거의 누구나 훈련없이 사용할 수 있기 때문이다. 하지만, 실제 작업에는 좀더 강력한 편집기 사용을 추천한다. 유닉스 시스템 계열(맥 OS X, 리눅스)에서 많은 프로그래머는 Emacs 혹은 Vim을 사용하거나, (둘다 완전히 비직관적이만, 심지어 유닉스 표준이기도 하다) 혹은 그래픽 편집기로 Gedit, VScode를 사용한다. 윈도우에서는 Notepad++를 사용하는 것도 좋다. 윈도우에는 메모장(notepad)이라고 불리는 자체 내장 편집기도 있는데 nano 편집기와 마찬가지로 명령라인에서 바로 불러 실행될 수 있다.

어떤 편집기를 사용하든, 파일을 검색하고 저장하는 것을 알 필요가 있다. 쉘에서 편집기를 시작하면, (아마도) 현재 작업 디렉토리가 디폴트 시작 위치가 된다. 컴퓨터 시작 메뉴에서 시작한다면, 대신에 바탕화면(Desktop) 혹은 문서(Document) 디렉토리에 파일을 저장하고 할 수 있다. 필요한 경우, “다른 이름으로 저장하기(Save As ...)” 명령어로 다른 디렉토리로 이동하여 작업 디렉토리를 변경한 후 파일을 저장한다.

그림 fig-nano 처럼 텍스트 몇 줄을 타이핑하자.

그림 3.1: nano 편집기 실제 사용화면

타이핑한 텍스트가 만족스럽다면, 컨트롤+O (Control-O, Ctrl 혹은 콘트롤 키보드를 누르면서 O 를 누름)를 눌러서 데이터를 디스크에 쓰면 저장된다. 저장하고자 하는 파일명을 입력하도록 독촉받게 되면 draft.txt 기본디폴트로 설정된 것을 받아들이고 엔터키를 친다.

파일이 저장되면, 컨트롤+X (Ctrl-X, Control-X)를 사용하여 편집기를 끝내고 쉘로 돌아간다.

주의

Control, Ctrl, ^ Key

컨트롤 키를 줄여서 “Ctrl” 키라고도 부른다. 컨트롤 키를 기술하는 몇가지 방식이 있다. 예를 들어, “컨트롤 키를 누른다”, “컨트롤 키를 누르면서 X 키를 친다”라는 표현은 다음 중 하나로 기술된다:

  • Control-X
  • Control+X
  • Ctrl-X
  • Ctrl+X
  • ^X
  • C-x

nano 편집기에서 화면 하단에 ^G Get Help ^O WriteOut을 볼 수 있다. Control-G를 눌러 도움말을 얻고, Control-O를 눌러 파일을 저장한다는 의미를 갖는다.

nano는 화면에 어떤 출력도 뿌려주지 않고 끝내지만, ls 명령어를 사용하여 draft.txt 파일이 생성된 것을 확인할 수 있다:

$ ls
draft.txt

예제 3.1 (다른 방법으로 파일 생성) nano 편집기를 사용해서 텍스트 파일을 생성하는 방법을 살펴봤다. 홈 디렉토리에서 다음 쉘 명령어를 실행해 보자:

$ cd                  # 홈 디렉토리로 이동하기
$ touch my_file.txt
  1. touch 명령어는 어떤 작업을 수행하는가? GUI 파일 탐색기를 사용해서 본인 홈 디렉토리를 살펴보게 되면, 파일이 생성된 것이 보이는가?
  2. ls -l 명령어를 사용해서 파일을 살펴보자. my_file.txt 파일크기는 얼마나 되는가?
  3. 이런 방식으로 파일을 언제 생성하면 좋을까?
정답과 설명
  1. touch 명령어가 홈 디렉토리에 ‘my_file.txt’ 파일을 새로 생성시킨다. 터미널로 현재 홈 디렉토리에 있는 경우, ls 를 타이핑하게 되면 새로 생성된 파일을 확인할 수 있다. GUI 파일 탐색기로도 ‘my_file.txt’ 파일을 볼 수 있다.

  2. ‘ls -l’ 명령어로 파일을 조사하게 되면, ‘my_file.txt’ 파일크기가 0kb 임에 주목한다. 다른 말로 표현하면, 데이터가 아무 것도 없다는 의미가 된다. 텍스트 편집기로 ‘my_file.txt’ 파일을 열게 되면, 텅 비어 있다.

  3. 일부 프로그램은 그 자체로 출력 파일을 생성하지 않지만, 빈 파일이 이미 생성되어 있는 것을 요구조건으로 하는 경우가 있다. 프로그램이 실행되면, 출력결과를 채울 수 있는 파일이 존재하는지 검색한다. 이런 프로그램에게 touch 명령어는 빈 텍스트 파일을 효율적으로 생성할 수 있는 메커니즘을 제공한다는 점에서 유용하다.

나중에 혼동을 피하려면 진도를 더 나가기 전에 방금 만든 파일을 제거하는 것이 좋다. 그렇지 않으면 향후 실행결과와 다를 수 있다. 이를 위해서 다음 명령을 실행한다:

$ rm my_file.txt
주의

파일명이 뭐가 중요해?

넬 박사 파일 이름이 “무엇.무엇”으로 된 것을 알아챘을 것이다. 이번 학습에서, 항상 .txt 확장자를 사용했다. 이것은 단지 관례다: 파일 이름을 mythesis 혹은 원하는 무엇이든지 작명할 수 있다. 하지만, 대부분의 사람들은 두 부분으로 구분된 이름을 사용하여 사람이나 프로그램이 다른 유형의 파일임을 구분하도록 돕는다. 이름에 나온 두번째 부분을 파일 확장자(filename extension)라고 부르고, 파일에 어떤 유형의 데이터가 담고 있는지 나타낸다. .txt 확장자는 텍스트 파일임을, .pdf는 PDF 문서임을, .cfg 확장자는 어떤 프로그램에 대한 구성정보를 담고 있는 형상관리 파일임을 내고, .png 확장자는 PNG 이미지 등등을 나타낸다.

단지 관습이기는 하지만 중요하다. 파일에는 바이트(byte) 정보만 담겨져 있다: PDF 문서, 이미지, 등에 대해서 규칙에 따라 바이트를 해석하는 것은 사람과 우리가 작성한 프로그램에 맡겨졌다.

whale.mp3처럼 고래 PNG 이미지 이름을 갖는 파일을 고래 노래의 음성파일로 변환하는 마술은 없다. 설사 누군가 두번 클릭할 때, 운영체제가 음악 재생기로 열어 실행할 수는 있지만 동작은 되지 않을 것이다.

3.3 파일과 디렉토리 이동

다음 명령어로 shell-lesson-data/exercise-data/writing 디렉토리로 돌아간다.

$ cd ~/Desktop/shell-lesson-data/exercise-data/writing

draft.txt가 특별한 정보를 제공하는 이름이 아니어서 mv를 사용하여 파일 이름을 변경하자. mv는 “move”의 줄임말이다:

$ mv thesis/draft.txt thesis/quotes.txt

첫번째 매개변수는 mv 명령어에게 이동하려는 대상을, 두번째 매개변수는 어디로 이동되는지를 나타낸다. 이번 경우에는 thesis/draft.txt 파일을 thesis/quotes.txt으로 이동한다. 이렇게 파일을 이동하는 것이 파일 이름을 바꾸는 것과 동일한 효과를 가진다. 아니나 다를까, ls 명령어를 사용하여 확인하면 thesis 디렉토리에는 이제 quotes.txt 파일만 있음을 확인할 수 있다:

$ ls thesis
quotes.txt

목표 파일명을 명세할 때 주의를 기울일 필요가 있다. 왜냐하면, mv 명령어는 동일 명칭을 갖는 어떤 기존 파일도 아주 조용히 덮어 써버리는 재주가 있어 데이터 유실에 이르게 된다. 부가적인 옵션 플래그, mv -i (즉 mv --interactive)를 사용해서 덮어쓰기 전에 사용자가 확인하도록 mv 명령어를 활용할 수도 있다.

일관성을 갖고 있어서, mv는 디렉토리에도 동작한다. 별도 mvdir 명령어는 없다.

quotes.txt 파일을 현재 작업 디렉토리로 이동하자. mv를 다시 사용한다. 하지만 이번에는 두번째 매개변수로 디렉토리 이름을 사용해서 파일이름을 바꾸지 않고, 새로운 장소에 놓는다. 이번 경우에 사용되는 디렉토리 이름은 앞에서 언급한 특수 디렉토리 이름 . 이다.

$ mv thesis/quotes.txt .

과거에 있던 디렉토리에서 파일을 현재 작업 디렉토리로 옮긴 효과가 나타난다. ls 명령어가 thesis 디렉토리가 비였음을 보여준다:

$ ls thesis

더 나아가, ls 명령어를 인자로 파일 이름 혹은 디렉토리 이름과 함께 사용하면, 그 해당 파일 혹은 디렉토리만 화면에 보여준다. 이렇게 사용하면, quotes.txt 파일이 현재 작업 디렉토리에 있음을 볼 수 있다:

$ ls quotes.txt
quotes.txt

예제 3.2 (현재 폴더로 이동하기) 다음 명령어를 실행한 후에, 정훈이는 sucrose.dat, maltose.dat 파일을 잘못된 폴더에 넣은 것을 인지하게 되었다:

$ ls -F
 analyzed/ raw/
$ ls -F analyzed
fructose.dat glucose.dat maltose.dat sucrose.dat
$ cd raw/

해당 파일을 현재 디렉토리(즉, 현재 사용자가 위치한 폴더)로 이동시키도록 아래 빈칸을 채우시오:

$ mv sucrose.dat maltose.dat ____/____
해답과 설명
$ mv sucrose.dat maltose.dat ../raw

.. 디렉토리는 부모 디렉토리(즉, 현재 디렉토리에서 상위 디렉토리를 지칭) . 디렉토리는 현재 디렉토리를 지칭함을 상기한다.

3.4 파일 및 디렉토리 복사

cp 명령어는 mv 명령어와 거의 동일하게 동작한다. 차이점은 이동하는 대신에 복사한다는 점이다. 인자로 경로를 두개 갖는 ls 명령어로 제대로 작업을 했는지 확인할 수 있다. 대부분의 유닉스 명령어와 마찬가지로, ls 명령어로 한번에 경로 다수를 전달할 수도 있다.

$ cp quotes.txt thesis/quotations.txt
$ ls quotes.txt thesis/quotations.txt
quotes.txt   thesis/quotations.txt

복사를 제대로 수행했는지 증명하기 위해서, 현재 작업 디렉토리에 있는 quotes.txt 파일을 삭제하고 나서, 다시 동일한 ls 명령어를 실행한다.

$ rm quotes.txt
$ ls quotes.txt thesis/quotations.txt
ls: cannot access quotes.txt: No such file or directory
thesis/quotations.txt

이번에는 현재 디렉토리에서 quotes.txt 파일은 찾을 수 없지만, 삭제하지 않은 thesis 폴더의 복사본은 찾아서 보여준다.

재귀 옵션 -r을 사용하여 디렉토리 및 디렉토리 내부 모든 콘텐츠를 복사할 수도 있다(예를 들어, 디렉토리를 백업하는 경우):

$ cp -r thesis thesis_backup

thesisthesis_backup 디렉토리 내부 결과를 ls 명령어로 확인할 수 있다:

$ ls thesis thesis_backup
thesis:
quotations.txt

thesis_backup:
quotations.txt

-r 플래그를 포함하는 것이 중요하다. 디렉토리를 복사하려는 경우 이 옵션을 생략하면 -r not specified 때문에 디렉토리가 생략되었다는 메시지가 표시된다.

$ cp thesis thesis_backup
cp: -r not specified; omitting directory 'thesis'

예제 3.3 (파일 이름 바꾸기) 데이터를 분석하는데 필요한 통계 검정 목록을 담고 있는 .txt 파일을 현재 디렉토리에 생성했다고 가정하자. 파일명은 statstics.txt. 파일을 생성하고 저장한 후에 곰곰히 생각해 보니 파일명 철자가 틀린 것을 알게 되었다! 틀린 철자를 바로잡고자 하는데, 다음 중 어떤 명령어를 사용해야 하는가?

  1. cp statstics.txt statistics.txt
  2. mv statstics.txt statistics.txt
  3. mv statstics.txt .
  4. cp statstics.txt .
해답과 설명
  1. No. 철자오류가 수정된 파일이 생성되지만, 철자가 틀린 파일도 디렉토리에 여전히 존재하기 때문에 삭제작업이 필요하다.
  2. Yes, 이 명령어를 통해서 파일명을 고칠 수 있다.
  3. No, 마침표(.)는 파일을 이동할 디렉토리를 나타내지 새로운 파일명을 제시하고 있지는 않고 있다. 동일한 파일명은 생성될 수 없다.
  4. No, 마침표(.)는 파일을 복사할 디렉토리를 나타내지 새로운 파일명을 제시하고 있지는 않고 있다. 동일한 파일명은 생성될 수 없다.

예제 3.4 (이동과 복사) 아래 보여진 일련의 명령문에 뒤에 ls명령어의 출력값은 무엇일까요?

$ pwd
/Users/jamie/data
$ ls
proteins.dat
$ mkdir recombine
$ mv proteins.dat recombine/
$ cp recombine/proteins.dat ../proteins-saved.dat
$ ls
  1. proteins-saved.dat recombine
  2. recombine
  3. proteins.dat recombine
  4. proteins-saved.dat
해답과 설명

/Users/jamie/data 디렉토리에서 출발해서, recombine 이름의 디렉토리를 새로 생성한다. 두번째 행은 proteins.dat 파일을 새로 만든 폴더 recombine으로 이동(mv) 시킨다. 세번째 행은 방금전에 이동한 파일에 대한 사본을 생성시킨다. 여기서 조금 까다로운 점은 파일이 복사되는 디렉토리다. .. 이 의미하는 바가 “한단계 위로 이동”하라는 의미라서, 복사되는 파일은 이제 /Users/jamie 디렉토리에 위치하게 됨을 상기한다. .. 이 의미하는 바는 복사되는 파일 위치에 대한 것이 아니라 현재 작업 디렉토리에 대한 것으로 해석됨에 유의한다. 그래서, 그래서, ls 명령어를 사용해서 보여지게 되는 것은 (/Users/jamie/data에 있기 때문에) recombine 폴더가 된다.

  1. No, 상기 해설을 참조한다. proteins-saved.dat 데이터는 /Users/jamie 폴더에 위치한다.
  2. Yes
  3. No, 상기 해설을 참조한다. proteins.dat 데이터는 /Users/jamie/data/recombine 폴더에 위치한다.
  4. No, 상기 해설을 참조한다. proteins-saved.dat 데이터는 /Users/jamie 폴더에 위치한다.

3.5 파일 및 디렉토리 제거

shell-lesson-data/exercise-data/writing 디렉토리로 돌아가서, 생성한 초안을 제거해서 thesis 디렉토리를 깔끔하게 정리하자. 이를 위해 사용할 유닉스 명령은 rm(’remove’의 줄임말)이다.:

$ cd thesis
$ rm draft.txt

상기 명령어는 파일을 제거한다(rm은 “remove”를 줄인 것이다.) ls 명령어를 다시 실행하게 되면, 출력결과는 아무 것도 없게 되는데 파일이 사라진 것을 확인시켜준다:

ls quotes.txt
ls: cannot access 'quotes.txt': No such file or directory
삭제는 영원하다

유닉스에는 삭제된 파일을 복구할 수 있는 휴지통이 없다. (하지만, 유닉스에 기반한 대부분의 그래픽 인터페이스는 휴지통 기능이 있다) 파일을 삭제하면 파일시스템의 관리대상에서 빠져서 디스트 저장공간이 다시 재사용되게 한다. 삭제된 파일을 찾아 되살리는 도구가 존재하지만, 어느 상황에서나 동작한다는 보장은 없다. 왜냐하면 파일이 저장되었던 공간을 컴퓨터가 바로 재사용할지 모르기 때문이다.

rm 안전하게 사용하기

rm -i thesis/quotations.txt 타이핑하면 무슨 일이 일어날까? rm 명령어를 사용할 때 왜 이러한 보호장치가 필요할까?

힌트
$ rm: remove regular file 'thesis/quotations.txt'?

-i 선택옵션은 삭제하기 전에 삭제를 확인하게 해준다. Y를 사용하여 삭제를 확인하거나 N을 사용하여 파일을 유지한다. 유닉스 쉘에는 휴지통이 없어서, 삭제되는 모든 파일은 영원히 사라진다. -i 플래그를 사용하게 되면, 삭제를 원하는 파일만 삭제되는지 점검할 수 있는 기회를 갖게된다.

rm thesis을 사용하여 전체 thesis 디렉토리를 제거하려고 하면 오류 메시지가 생긴다:

$ rm thesis
rm: cannot remove `thesis': Is a directory

rm 명령어는 파일에만 동작하고 디렉토리에는 동작하지 않기 때문에 오류가 발생한다. thesis 디렉토리를 제거하려면, draft.txt 파일도 삭제해야 한다. rm 명령어에 재귀(recursive) 선택옵션을 사용해서 삭제 작업을 수행할 수 있다:

$ rm -r thesis

쉘을 사용하여 삭제한 파일을 복원할 수 있는 방법이 없으므로 rm -r은 매우 주의해서 사용해야 한다 (대화형 옵션인 rm -r -i를 추가하는 것도 고려해 볼 수 있다).

큰 힘에는 큰 책임이 따른다

디렉토리를 삭제하려고 할 때, 먼저 파일을 제거하고 그리고 나서 디렉토리를 제거하는 방식은 지루하고 시간이 많이 걸린다. 대신에 -r 옵션을 가진 rm 명령어를 사용할 수 있다. -r 플래그 옵션은 “recursive(재귀적)”을 나타낸다.

$ rm -r thesis

디렉토리에 모든 것을 삭제하고 나서 디렉토리 자체도 삭제한다. 만약 디렉토리가 하위 디렉토리를 가지고 있다면, rm -r은 하위 디렉토리에도 같은 작업을 반복한다. 매우 편리하지만, 부주위하게 사용되면 피해가 엄청날 수 있다.

디렉토리와 파일을 재귀적으로 제거하는 것은 매우 위험할 수 있다. 삭제되는 것에 염려가 된다면, rm 명령어에 -i 인터랙티브 플래그를 추가해서 삭제단계마다 확인을 하고 삭제하는 것도 가능하다.

$ rm -r -i thesis
rm: descend into directory ‘thesis’? y
rm: remove regular file ‘thesis/draft.txt’? y
rm: remove directory ‘thesis’? y

상기 명령어는 thesis 디렉토리 내부 모든 것을 삭제하고 나서 thesis 디렉토리도 삭제하는데 삭제단계별로 확인 절차를 거친다.

3.6 다수 파일과 폴더 작업

한번에 여러 파일을 복사하거나 이동해야 하는 경우가 종종 있다. 파일명을 목록으로 제공하거나 와일드카드를 사용하여 패턴을 지정하면 된다. 와일드카드(Wildcards)는 Unix 파일 시스템을 탐색할 때 특정한 패턴이나 일련의 문자를 대체하거나 대표하는 데 사용되는 특수 문자로 *, ?, % 등이 대표적이다.

예제 3.5 (다수 파일을 복사하기) 이번 연습문제에서는 data-shell/data 디렉토리에서 명령어를 테스트한다. 아래 예제에서, 파일명 다수와 디렉토리명이 주어졌을 떄 cp 명령어는 어떤 작업을 수행하는가?

$ mkdir backup
$ cp amino-acids.txt animals.txt backup/

아래 예제에서, 3개 혹은 그 이상의 파일명이 주어졌을 때 cp 명령어는 어떤 작업을 수행하는가?

$ ls -F
amino-acids.txt  animals.txt  backup/  elements/  morse.txt  pdb/  planets.txt  salmon.txt  sunspot.txt
$ cp amino-acids.txt animals.txt morse.txt 
해답과 설명

하나 이상의 파일명 다음에 디렉토리명이 주어지게 되면, 다시말해 목적지 디렉토리는 마 지막 인자에 위치해야 하는데, cp 명령어는 파일을 해당 디렉토리에 복사한다.

연달아 파일명이 세게 주어지면, cp 명령어는 오류를 던지는데 이유는 마지막 인자로 디렉토리를 기대했기 때문이다.

cp: target ‘morse.txt’ is not a directory

3.7 와일드카드 한번 사용으로 여러 파일에 접근

와일드 카드(Wildcards)

*와일드카드(wildcard)다. 와일드카드는 0 혹은 그 이상의 문자와 매칭되서, *.pdbethane.pdb, propane.pdb 등등에 매칭한다. 반면에, p*.pdbpropane.pdbpentane.pdb만 매칭하는데, 맨 앞에 ’p’로 시작되는 파일명만 일치하기만 하면 되기 때문이다.

?도 또한 와일드카드지만 단지 단일 문자만 매칭한다. 이것이 의미하는 바는 p?.pdbpi.pdb 혹은 p5.pdb을 매칭하지만 (molecules 디렉토리에 두 파일이 있다면), propane.pdb은 매칭하지 않는다. 한번에 원하는 수만큼 와일드카드를 사용할 수 있다.

예를 들어, p.p?p로 시작하고 .p, 그리고 최소 한자 이상의 문자로 끝 나는 임의의 문자열을 매칭한다고 표현할 수 있는데 ?이 한 문자를 매칭해야하고 마지막 은 끝에 임의의 문자숫자와 매칭할 수 있기 때문이다. 그래서 p*.p?*preferred.practice과 심지어 p.pi도 매칭한다(첫번째 은 어떤 문자도 매칭할 수가 없음). 하지만 quality.practice은 매칭할 수 없는데 이유는 ‘p’로 시작하지 않고, preferred.p도 매칭할 수 없는데 ’p’ 다음에 최소 하나의 문자가 필요한데 없기 때문이다.

쉘이 와일드카드를 봤을 때, 요청된 명령문을 시작하기 전에 와일드카드를 확장하여 매칭할 파일 이름 목록을 생성한다. 예외로, 와일드카드 표현식이 어떤 파일과도 매칭되지 않게되면, 배수는 명령어에 인자로 표현식을 있는 그대로 전달한다. 예를 들어, molecules 디렉토리(.pdb 확장자로 끝나는 파일만 모여있다.)에 ls *.pdf을 타이핑하게 되면, *.pdf으로 불리는 파일이 없다고 오류 메시지를 출력한다. 하지만, 일반적으로 wcls 명령어는 와일드카드 표현식과 매칭되는 파일명 목록을 보게 되고 와일드카드 자체가 아니다. 다른 프로그램은 아니지만, 쉘은 와일드카드를 확장한 것을 다룬다는 점에서 직교 설계(orthogonal design)의 또 다른 사례로 볼 수 있다.

예제 3.6 (와일드카드 추가 문제) 정훈이는 미세조정(calibration), 원본 데이터(dataset), 데이터 설명 데이터를 디렉토리에 보관하고 있다:

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
   ├── calibration
   └── datasets
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
    └── all_november_files

또 다른 견학여행을 떠나기 전에, 정훈이는 데이터를 백업하고 일부 데이터를 연구실 동료 기민에게 보내고자 한다. 정훈이는 백업과 전송 작업을 위해서 다음 명령어를 사용한다:

$ cp *dataset* /backup/datasets
$ cp ____calibration____ /backup/calibration
$ cp 2015-____-____ ~/send_to_bob/all_november_files/
$ cp ____ ~/send_to_bob/all_datasets_created_on_a_23rd/

정훈이가 빈칸을 채우도록 도움을 주세요. 작업결과 디렉토리 구조는 다음과 같아야 한다.

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
   ├── calibration
   │   ├── 2015-10-23-calibration.txt
   │   ├── 2015-10-26-calibration.txt
   │   └── 2015-11-23-calibration.txt
   └── datasets
       ├── 2015-10-23-dataset1.txt
       ├── 2015-10-23-dataset2.txt
       ├── 2015-10-23-dataset_overview.txt
       ├── 2015-10-26-dataset1.txt
       ├── 2015-10-26-dataset2.txt
       ├── 2015-10-26-dataset_overview.txt
       ├── 2015-11-23-dataset1.txt
       ├── 2015-11-23-dataset2.txt
       └── 2015-11-23-dataset_overview.txt
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
       ├── 2015-10-23-dataset1.txt
       ├── 2015-10-23-dataset2.txt
       ├── 2015-10-23-dataset_overview.txt
       ├── 2015-11-23-dataset1.txt
       ├── 2015-11-23-dataset2.txt
       └── 2015-11-23-dataset_overview.txt
    └── all_november_files
        ├── 2015-11-23-calibration.txt
        ├── 2015-11-23-dataset1.txt
        ├── 2015-11-23-dataset2.txt
        └── 2015-11-23-dataset_overview.txt
해답과 설명
$ cp *calibration.txt /backup/calibration
$ cp 2015-11-* ~/send_to_bob/all_november_files/
$ cp *-23-dataset* ~send_to_bob/all_datasets_created_on_a_23rd/

예제 3.7 (디렉토리와 파일 조직화) 정훈이가 프로젝트 작업을 하고 있는데, 작업 파일이 그다지 잘 조직적으로 정리되어 있지 않음을 알게 되었다:

$ ls -F
analyzed/  fructose.dat    raw/   sucrose.dat

fructose.datsucrose.dat 파일은 자료분석 결과 산출된 출력결과를 담고 있다. 이번 학습에서 배운 어떤 명령어를 사용해서 아래 명령어를 실행했을 때 다음에 보여지는 출력을 생성할까요?

$ ls -F
analyzed/   raw/
$ ls analyzed
fructose.dat    sucrose.dat
해답과 설명
$ mv *.dat analyzed

정훈이는 analyzed 디렉토리에 fructose.dat, sucrose.dat 파일을 이동시킬 필요가 있다. 쉘에서 현재 디렉토리에서 *.dat 와일드카드가 .dat 확장자를 갖는 모든 파일을 매칭한다. mv 명령어가 .dat 확장자를 갖는 파일을 analyzed 디렉토리로 이동시킨다.

예제 3.8 (폴더 구조 재현) 새로운 실험을 시작해 보자. 데이터 파일 없이 이전 실험에게 만들었던 디렉토리 구조만 복제하자. 그렇게 하면 새로운 데이터를 쉽게 추가할 수 있게 된다. ‘2016-05-18-data’ 디렉토리에 data 폴더로 rawprocessed가 있는데, 각자 데이터 파일이 담겨있다.

목적은 2016-05-18-data 폴더를 2016-05-20-data 폴더로 복사하는 것인데 복사된 폴더에는 모든 데이터 파일을 제거해야 된다. 다음 명령어 집합 중 어떤 명령어 집합이 상기 목적을 달성할까요? 다른 명령어 집합은 무슨 작업을 수행하는 것일까?

이전 실험이 2016-05-18이라는 폴더에 있고, 이 폴더에는 데이터 폴더가 있으며, 이 폴더에는 차례로 데이터 파일이 들어 있는 rawprocessed라는 이름의 폴더가 있다고 가정하자. 목표는 2016-05-18 폴더의 폴더 구조를 2016-05-20이라는 폴더에 복사하여 최종 디렉토리 구조가 다음과 같이 되도록 하는 것이다:

2016-05-20/
└── data
   ├── processed
   └── raw

다음 중 이 목표를 달성할 수 있는 쉘 명령은 무엇인가요? 다른 쉘명령은 무슨 작업을 수행하나요?

$ mkdir 2016-05-20
$ mkdir 2016-05-20/data
$ mkdir 2016-05-20/data/processed
$ mkdir 2016-05-20/data/raw
$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ cd data
$ mkdir raw processed
$ mkdir 2016-05-20/data/raw
$ mkdir 2016-05-20/data/processed
$ mkdir -p 2016-05-20/data/raw
$ mkdir -p 2016-05-20/data/processed
$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ mkdir raw processed
해답과 설명

처음 두 쉘 명령은 목적을 달성한다. 첫 번째 쉘명령은 상대 경로를 사용하여 하위 디렉토리 앞에 최상위 디렉토리를 만든다.

세 번째 쉘명령은 mkdir 기본 동작이 존재하지 않는 디렉토리의 하위 디렉토리를 만들지 않는다. 따라서, 중간에 폴더를 먼저 만들어야 하기 때문에 오류를 발생된다.

네 번째 쉘명령도 목적을 달성한다. 하나 이상의 디렉토리 경로 뒤에 -p 옵션을 사용하면 mkdir 필요에 따라 중간 하위 디렉토리를 만들게 된다는 점을 기억한다.

마지막 쉘명령은 ‘data’ 디렉토리와 같은 수준에서 ‘raw’ 및 ‘processed’ 디렉토리를 생성한다.

파일명 변경

thesis\ 디렉토리에 위치한 draft.txt 파일명을 thesis.txt 파일로 파일명을 변경해보자.

프롬프트: shell-lesson-data/exercise-data/writing/thesis 디렉토리로 이동한 후 touch 명령어로 draft.txt 파일을 생성한 후 파일명을 thesis.txt 파일로 변경하세요.

$ sgpt -s "shell-lesson-data/exercise-data/writing/thesis 디렉토리로 이동한 후 touch 명령어로 draft.txt 파일을 생성한 후 파일명을 thesis.txt 파일로 변경하세요."
cd shell-lesson-data/exercise-data/writing/thesis && touch draft.txt && mv draft.txt thesis.txt
[E]xecute, [D]escribe, [A]bort: D
This command changes the current directory to "shell-lesson-data/exercise-data/writing/thesis",E creates a new file called "draft.txt", and then renames the file to "thesis.txt".
[E]xecute, [D]escribe, [A]bort: E
$ ls shell-lesson-data/exercise-data/writing/thesis
thesis.txt

챗GPT가 프롬프트로 작성한 유닉스 쉘 명령어를 해석하면 다음과 같다.

디렉토리를 “shell-lesson-data/exercise-data/writing/thesis”로 변경하고, E는 “draft.txt”라는 새 파일을 생성한 다음 파일 이름을 “thesis.txt”로 변경한다.

sgpt 프롬프트를 실행하게 되면 draft.txt 파일이 touch 명령어로 생성되고 mv 명령어로 thesis.txt 파일로 파일명이 변경된다.

데이터 사이언스 프로젝트 백업

데이터 과학 프로젝트는 데이터 가져오기, 정제, EDA, 보고서 작성 등 각 단계별로 세분화되어 있다. 그리고 프로젝트가 종료되면 백업하여 혹시 모른 사태에 대비하거나 후속 프로젝트에 활용할 수 있도록 관리를 한다.

프롬프트: shell-lesson-data/exercise-data/writing/thesis 디렉토리로 이동한 후 touch 명령어로 data.sql, clean.py, EDA.R, report.qmd 파일을 생성한 후 thesis/ 디렉토리에 있는 모든 파일을 상 위 디렉토리에 backup/ 디렉토리를 생성하고 복사하여 백업하세요.

$ sgpt -s "shell-lesson-data/exercise-data/writing/thesis 디렉토리로 이동한 후 touch 명령어로 data.sql, clean.py, EDA.R, report.qmd 파일을 생성한 후 thesis/ 디렉토리에 있는 모든 파일을 상
위 디렉토리에 backup/ 디렉토리를 생성하고 복사하여 백업하세요."
cd shell-lesson-data/exercise-data/writing/thesis && touch data.sql clean.py EDA.R report.qmd && mkdir ../backup && cp * ../backup
[E]xecute, [D]escribe, [A]bort: D
This command changes the current directory to "shell-lesson-data/exercise-data/writing/thesis", creates four files named "data.sql", "clean.py", "EDA.R", and "report.qmd" in that directory, creates a new directory named "backup" in the parent directory, and copies all the files in the current directory to the "backup" directory.
[E]xecute, [D]escribe, [A]bort: E
statkclee@dl:/mnt/c/Users/statkclee/OneDrive/Desktop$ ls shell-lesson-data/exercise-data/writing/backup/
clean.py  data.sql  EDA.R  report.qmd  thesis.txt

챗GPT가 프롬프트로 작성한 유닉스 쉘 명령어를 해석하면 다음과 같다.

디렉터리를 “shell-lesson-data/exercise-data/writing/thesis”로 변경하고, 해당 디렉토리에 “data.sql”, “clean.py”, “EDA.R” 및 “report.qmd”라는 4개의 파일을 생성하고, 상위 디렉토리에 “backup”이라는 새 디렉토리를 생성한 후 현재 디렉토리의 모든 파일을 “backup” 디렉토리로 복사한다.

실행하게 되면 backup 디렉토리가 생성되고 데이터 사이언스 관련 모든 파일이 복사된 것이 확인된다.