GNU-Linux

UNIX as IDE: 2. Files

동건 2017. 11. 6. 01:28

이 시리즈의 원 저자인 Tom Ryder의 허락을 받고 올리는 번역글입니다. IDE가 할 수 있는 기능을 UNIX 계열의 shell 안에서도 원활하게 할 수 있는 비결을 초보자도 알기 쉽게 잘 설명한 글일 뿐만 아니라 UNIX 자체의 철학이나 기본 사용법을 따라잡기에도 굉장히 좋은 글이라 생각되어 우리말로 옮기고자 합니다. 프로그래밍 용어는 웬만하면 원래 영단어로 쓰겠습니다. 언제든지 더 좋은 표현에 대한 의견은 감사합니다.



UNIX as IDE: Files

2012년 2월 10일 Tom Ryder가 작성


IDE의 한 가지 두드러진 특징은 파일 관리를 위한 내장 시스템이다. 여기서 파일 관리는 이동, 이름 바꾸기 및 삭제와 같은 기본 기능과 compiling 및 syntax 검사와 같은 개발 관련 기능을 포함한다. 또한 확장자나 파일 크기에 따라 여러 파일을 찾는다든지, 특정 패턴을 갖고 있는 파일을 검색하는 것도 유용한 기능이 될 것이다. 이 글에서는 대부분의 GNU/Linux 사용자가 익숙하게 사용할 수 있는 도구를 사용해서 프로젝트의 여러 파일을 다루는 방법을 살펴보려 한다.



파일 리스트 보기

ls는 아마도 사용자가 디렉토리 내 파일 목록을 보기 위해 배우게 되는 가장 첫 번째 명령일 것이다. 그리고 -a 및 -l 옵션은 대부분 알텐데, 숨겨진 파일(dot files)을 포함하고 상세 정보를 표시하는 것이다.


-al 보다는 덜 사용되는 옵션들이긴 하지만, 프로그래밍을 하면서 꽤나 유용하게 사용할 수 있는 것들이 있다.

  • -t — 최근 변경일 기준으로 최신 순서로 정렬, 가장 최근에 변경된 파일의 quick list를 보는 데 유용한데, 특히 head나 seq 10q와 pipe로 연결될 수 있다. 아마도 -l과 궁합이 제일 잘 맞을 듯. 가장 오래된 파일을 보고 싶다면 -r로 정렬 순서를 뒤집으면 된다.
  • -X — 확장자 별로 그룹을 묶는다. Polyglot 프로젝트에서 잘 쓰일 수 있다. 헤더와 소스 파일, 소스 파일과 빌드 파일 또는 디렉토리 등을 구분 짓고 싶을 때도 쓰인다.
  • -v — 파일명에 있는 버전 숫자대로 정렬한다.
  • -S — 파일 크기 별로 정렬.
  • -R — 하위 폴더까지 모두 리스트. -l과 함께 less와 같은 pager에 pipe 연결로 잘 쓰인다.


명령의 결과로 볼 수 있는 목록은 결국 텍스트다. 다른 텍스트와 다를 것이 전혀 없다. 따라서 이 명령의 결과를 Vim 프로세스에 넘겨서(pipe) 각 파일들에 대한 추가 사항을 적어서 README로 저장할 수도 있다.

$ ls -XR | vim -


이런 작업들은 조금만 공을 들이면 자동화할 수 있는데, 나중에 다루도록 하겠다.



파일 찾기

(위에서 ls와 pipe을 통해서 여러 작업을 했지만) 재밌게도, 하위 폴더를 포함한 모든 파일 리스트를 군더더기 없이 깔끔하게 find . 만으로도 확인할 수 있다. 아래 예제는 그 결과를 다시 sort에 pipe로 넘긴 결과이다.

$ find . | sort
.
./Makefile
./README
./build
./client.c
./client.h
./common.h
./project.c
./server.c
./server.h
./tests
./tests/suite1.pl
./tests/suite2.pl
./tests/suite3.pl
./tests/suite4.pl



ls -l 스타일의 목록을 보고 싶다면, -ls 옵션을 줘서 GNU find(1) 결과물에 어떤 action을 줄 수도 있다.

$ find . -ls | sort -k11,11
1155096    4 drwxr-xr-x   4 tom      tom          4096 Feb 10 09:37 .
1155152    4 drwxr-xr-x   2 tom      tom          4096 Feb 10 09:17 ./build
1155155    4 -rw-r--r--   1 tom      tom          2290 Jan 11 07:21 ./client.c
1155157    4 -rw-r--r--   1 tom      tom          1871 Jan 11 16:41 ./client.h
1155159   32 -rw-r--r--   1 tom      tom         30390 Jan 10 15:29 ./common.h
1155153   24 -rw-r--r--   1 tom      tom         21170 Jan 11 05:43 ./Makefile
1155154   16 -rw-r--r--   1 tom      tom         13966 Jan 14 07:39 ./project.c
1155080   28 -rw-r--r--   1 tom      tom         25840 Jan 15 22:28 ./README
1155156   32 -rw-r--r--   1 tom      tom         31124 Jan 11 02:34 ./server.c
1155158    4 -rw-r--r--   1 tom      tom          3599 Jan 16 05:27 ./server.h
1155160    4 drwxr-xr-x   2 tom      tom          4096 Feb 10 09:29 ./tests
1155161    4 -rw-r--r--   1 tom      tom           288 Jan 13 03:04 ./tests/suite1.pl
1155162    4 -rw-r--r--   1 tom      tom          1792 Jan 13 10:06 ./tests/suite2.pl
1155163    4 -rw-r--r--   1 tom      tom           112 Jan  9 23:42 ./tests/suite3.pl
1155164    4 -rw-r--r--   1 tom      tom           144 Jan 15 02:10 ./tests/suite4.pl

-k 옵션을 통해서 11번째 열을 기준으로 (파일 이름 기준) 정렬한 것이다.


find는 복잡한 필터 문맥을 가지고 있다. 아래에 가장 유용할 수 있는 예시를 모아봤다.

  • find . -name '*.c' — shell-style 패턴에 맞는 파일 이름으로 찾는다. 대소문자를 구분하지 않으려면 -iname
  • find . -path '*test*' — shell-style 패턴에 맞는 파일 경로로 찾는다. 대소문자를 구분하지 않으려면 -ipath
  • find . -mtime -5 — 변경 날짜가 최근 5일 안에 있는 파일을 찾는다. 그 반대로, 변경된 지 5일이 지난 파일을 찾으려면 +5
  • find . -newer server.c — server.c보다 최근에 변경된 파일을 찾는다.
  • find . -type d — 디렉토리를 대상으로 찾는다. -type f는 파일 대상으로,-type l는 바로가기를 대상으로 찾는다.

이 명령 옵션들이 모두 조합될 수 있다는 점도 알아두자. 예를 들어 ...

$ find . -name '*.c' -mtime -2


find의 기본 action으로 그 결과를 standard output에 보여주지만, 다른 유용한 action도 있다.

  • -ls — 위에서 소개한 대로 ls -l 스타일로 리스트 출력, (GNU find(1)) 참조
  • -delete — 찾은 파일 삭제
  • -exec — 파일에 대해 원하는 명령을 실행시키는데, {}를 찾은 파일로 대체해서 명령에게 알려준다. 그리고 \;로 명령의 끝을 알려준다. 예를 들면

    $ find . -name '*.pl' -exec perl -c {} \;


    명령어를 단 한 번만 실행시키면서 find에서 찾은 모든 파일을 넘겨주고 싶다면 +로 명령의 끝을 알리면 된다. 아래 예시는 찾은 파일을 모두 vim의 쪼개진 창으로 여는 명령이다.

    $ find . -name '*.c' -exec vim {} +


필자의 추가 사항: 과거에 find의 결과물에 이은 action을 위해서 xargs를 소개했었다. 하지만 대부분의 경우에는 xargs가 필요하지 않을 뿐 더러, -exec 또는 while read -r 반복문을 이용하는 것이 훨씬 안전한 방법이다.



파일 검색

파일 자체의 내용으로 검색하기 보다는 파일 내용에 대해 검색하고 싶을 때가 더 많다. 이럴 때 grep -R을 쓸 수 있는데, 하위 폴더를 포함해서 someVar가 쓰여진 파일들을 찾는다.

$ grep -FR someVar .


grep은 기본적으로 대소문자를 구별하기 때문에, 대소문자를 구분하지 않는 옵션도 잊으면 안된다.

$ grep -iR somevar .


또한 -l 옵션을 통해 상세 정보 없이 파일 경로만 출력할 수 있다.

$ grep -lR someVar .


위 명령의 결과를 이용해서 스크립트를 짠다거나 batch job을 돌린다면, while loop에 read를 통해 파일 이름에 있는 공백 및 여타 특수 문자를 다룰 수 있다.

grep -lR someVar | while IFS= read -r file; do
    head "$file"
done



버전 관리 도구를 이용해서 프로젝트를 진행하고 있다면, .svn, .git, .hg와 같은 버전 메타데이터 디렉토리가 grep 결과에 포함된다. 이를 해결하기 위해서는 -F로 메타데이터 폴더를 찾고 -v를 통해 그 결과를 제외시키면 된다.

$ grep -R someVar . | grep -vF .svn

--exclude과 --exclude-dir 옵션을 탑재한 버전의 grep이라면, 위 명령보다는 훨씬 깔끔하게 쓸 수 있을 것이다.


한편, 새로운 grep인 ack라는 이미 유명한 프로그램도 있다. ack은 기본적으로 버전 관리 도구가 만들어내는 메타데이터 내용을 기본적으로 제외시킨다. 많은 프로그래머들이 선호하는 Perl 호환 정규 표현식 (PCRE)을 사용할 수도 있다. 만약 ack를 설치할 수 있는 환경이라면 ack을 꽤나 추천하고 싶다. 물론 우리의 오래된 친구 grep이 잘못한 것은 없고 항상 grep은 우리 곁에 있겠지만, ack은 소스 코드로 작업하는 일반적인 상황에서 유용한 기능이 많기 때문이다. 데비안에는 ack-grep이라는 데비안 패키지가 있는데, Perl 스크립트라는 것이 신경쓰이지만 않는다면 매우 간단하게 설치할 수 있다.


UNIX 순수주의자(purist)들은 클래식 grep에 비해서 새로운 Perl 스크립트를 언급하는 것만으로도 불만스러울 지 모르지만, 나는 UNIX 정신을 가지면서 새로운 문제를 해결할 수 있는 대안이 있는데 옛 것을 고집하는 것이 유닉스 철학이라고 생각하지 않으며, UNIX as IDE에 맞는 태도라고도 생각하지 않는다.



파일 metadata

file 도구는 파일의 확장자, 헤더 등을 기반으로 한 줄 요약 정보를 보여준다. find와 연계해서 낯선 파일을 조사할 때 유용하게 쓰인다.

$ find . -exec file {} +
.:            directory
./hanoi:      Perl script, ASCII text executable
./.hanoi.swp: Vim swap file, version 7.3
./factorial:  Perl script, ASCII text executable
./bits.c:     C source, ASCII text
./bits:       ELF 32-bit LSB executable, Intel 80386, version ...




파일 매칭

마지막 팁을 주자면, bash의 패턴 찾는 방법과 {}를 이용한 확장 방법을 알아두는 것을 추천한다. 이와 관련한 필자의 다른 글 Bash shell expansion을 참조바란다.

이 글에서 다룬 기능을 통해 클래식 UNIX shell이 프로젝트 파일을 관리하는 데 꽤나 강력한 모습을 보여줄 수 있다.


2017년 4월 필자의 추가사항: 대부분의 find 예제를 POSIX 호환되도록 변경했음



UNIX as IDE




반응형

'GNU-Linux' 카테고리의 다른 글

UNIX as IDE: 4. Compiling  (0) 2017.11.06
UNIX as IDE: 3. Editing  (0) 2017.11.06
UNIX as IDE: 1. Introduction  (0) 2017.11.06
Vim 사용자가 되기 위한 첫 걸음 (.feat tmux)  (1) 2017.10.06
Linux 초보의 tmux (terminal multiplexer) 입문  (6) 2017.10.05