이 시리즈의 원 저자인 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
스타일로 리스트 출력, (GNUfind(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 |