Modern Unix — Part 2
[들어가며]
지난 시간에는 exa
(ls
), bat
(cat
), delta
(diff
), dust
(du
), duf
(df
)를 소개해 드렸습니다. 앞의 도구들은 단일 실행으로 비교적 간단하게 사용할 수 있는 도구들인데요. 오늘 소개해 드리려는 도구들은 보통 다른 도구들과 파이프로 결합하여 사용할 때 더 유용한 도구들입니다.
[fd]
원하는 파일을 찾을 때 사용하는 find
는 자주 사용하게 되는 명령어 중에 하나인데요. 보통 파일을 찾을 때, 파일 명을 기준으로 찾는 경우가 많다 보니, 검색 조건에 반복적인 -name
옵션이나 -iname
(대소문자 무시) 옵션을 붙이는 경우가 많습니다. fd
는 기본으로 -iname
옵션을 붙이지 않아도 되는데요. vim을 써보셨으면 아실만한 smart case를 기본으로 지원합니다.
- 직관적인 구문:
find -iname '*PATTERN*'
대신fd PATTERN
- 정규식(기본값) 및 glob 기반 패턴
- 병렬화된 디렉토리 탐색으로 매우 빠릅니다.
- 색상을 사용해 다양한 파일 유형을 강조 표시합니다(
ls
와 동일). - 병렬 명령 실행 지원
- 스마트 케이스: 검색은 기본적으로 대소문자를 구분하지 않습니다. 패턴에 대문자가 포함되어 있으면 대소문자를 구분하는 것으로 전환됩니다.
- 기본적으로 숨겨진 디렉토리와 파일을 무시합니다.
- 기본적으로
.gitignore
의 패턴을 무시합니다. fd
은find
보다 50% 짧습니다 :-)
[ripgrep]
여러분은 어떤 도구를 가장 유용하게 사용하고 계신가요? 저는 Unix를 매우 강력하게 활용할 수 있게 해주는 도구가 바로 grep
이라고 생각하는데요. 여러분들 생각은 어떠신가요? 물론 grep
자체로도 이미 훌륭하지만. grep
보다 더 빠르며, 여러 가지 편의 기능을 추가한 ripgrep을 소개해 드리겠습니다. 참고로 명령어는 ripgrep이 아니라 rg
로 입력합니다.
grep
이 지원하는 대부분의 기능을 모두 지원: 검색 결과의 전후 문맥 표시, 여러 패턴 검색, 매치 결과 하이라이팅, 유니코드 지원 (grep
과 다르게 유니코드 지원이 항상 켜져 있으며, 켜져 있어도 빠른 속도를 유지)- 기본적으로 재귀 검색 수행 (서브 디렉터리)
- 기본적으로 숨김 폴더 및 파일은 무시
- 기본적으로
.gitignore
에서 설정한 내용은 무시 - 특정 타입의 파일 지정/제외 가능:
rg -tpy pattern
파이썬 파일에서만 검색,rg -Tjs pattern
자바스크립트 파일을 검색에서 제외 - 정규 표현식 엔진을 PCRE2로 변경함으로써 전후방탐색(look-around) 및 역참조(backreference) 지원
- 매칭된 패턴의 기초적인 바꾸기(replace) 기능 제공
- UTF-8뿐 아니라 UTF-16, latin-1, GBK, EUC-JP, Shift-JIS등 다양한 텍스트 인코딩 탐색 지원
- 일반적인 형식(brotli, bzip2, gzip, lz4, lzma, xz, 또는 zstandard)으로 압축된 파일 검색을 지원
- PDF 텍스트 추출, 마이너 한 압축 포맷의 해제, 복호화, 자동 인코딩 감지 등 임의의 입력 전처리 필터를 지원
- 설정 파일을 통해 설정 가능
이 중에 특정 파일 타입을 제외하는 기능이 매우 유용합니다. minified된 스크립트는 보통 한 줄로 되어 있어서 매칭이 쉽게 될뿐더러, 출력을 어지럽히니까요. .gitignore
에 지정해둔 파일을 검색하지 않는 것 또한 현대식 도구가 가진 특징이라 볼 수 있겠네요.
[fzf]
리스트에서 하나의 아이템만 선택하려면 어떻게 할까요? 보통 grep
, head
, tail
등을 이용하실 텐데요. 더 직관적이고 빠른 방법으로 이 작업을 할 수 있는 도구가 있습니다. fzf
는 표준 입력으로 줄바꿈으로 구분된 리스트를 전달받아, 사용자의 실시간 피드백을 받은 후, 선택된 항목을 표준 출력으로 표시합니다. fzf
로 파일 리스트, 커맨드 히스토리, 프로세스, git
커밋 등 모든 리스트에서 원하는 항목을 즉각적으로 찾을 수 있습니다.
- 휴대성(정적 링크된 단일 바이너리), 의존성 없음
- 빠른 속도
- 종합적인 기능 세트
- 화면 크기에 따른 유연한 레이아웃
- Vim/Neovim 플러그인, 키 바인딩 및 퍼지 자동 완성 기능
fzf를 아무런 인자 없이 실행하면, 현재 및 하위 디렉터리에 있는 파일 목록이 입력이 됩니다(숨겨진 파일 제외). 다음 명령을 실행하여 어떤 일이 벌어지는지 확인해 보세요.
vim $(fzf)
또한 이전에 소개해 드린 bat
와 결합하면, 파일을 선택하기 전에 미리 보면서 선택할 수도 있습니다.
fzf --preview 'bat -f {}'
참고로 이 도구는 vim-plug의 제작자분께서 만드셨는데요. 한국 분이라고 합니다! 펄럭~🇰🇷 👏👏👏
[McFly]
이전에 입력했던 명령어를 다시 입력해야 할 때 보통 Ctrl+R(명령 줄 히스토리 검색)로 확인을 하죠. 이제 이 작업마저도 현대식으로 대체되었습니다. mcfly
라는 도구는 단순히 과거의 명령어를 순차적으로 보여주는 것이 아니라, 현재 작업 디렉터리 및 명령어 순서, 과거 종료 코드 등 여러가지 상황들을 고려하여, 커맨드 히스토리에서 실시간으로 우선순위가 정해져서 사용자에게 제안합니다.
- ctrl-r을 다시 바인딩 하여 소규모 신경망으로 우선순위를 지정한 전체 화면 역방향 기록 검색을 불러옵니다.
- 셸 히스토리를 강화하여 명령 종료 상태, 타임스탬프, 실행 디렉터리를 SQLite 데이터베이스에서 추적합니다.
- 일반 셸 히스토리 파일도 유지하므로 원할 때 언제든지 McFly 사용을 중지할 수 있습니다.
- 전체 유니코드 지원.
- McFly 데이터베이스와 셸 히스토리 파일에서 모든 히스토리 항목을 스크러빙하는 간단한 작업이 포함되어 있습니다.
- 향후 다른 셸에도 확장할 수 있도록 설계되었습니다.
- Rust로 작성되어 빠르고 안전합니다.
- 검색할 때 %를 입력하여 원하는 수의 문자와 일치 시킬 수 있습니다.
McFly의 핵심은 결국 우선순위를 지정하는 알고리즘에 있는데요. 사용자의 의도를 정확히 파악하여 사용자가 원하는 명령이 가장 먼저 제안 되도록 하는 것이 이 도구의 목표라고 합니다. 명령을 제안할 때 McFly는 다음 사항을 고려합니다:
- 명령을 실행한 디렉토리. 나중에 같은 디렉토리에서 해당 명령을 실행할 가능성이 높기 때문입니다.
- 명령 전에 입력한 명령(예: 명령의 실행 컨텍스트).
- 명령을 실행하는 빈도.
- 마지막으로 명령을 실행한 시간.
- 이전에 맥플라이에서 해당 명령을 선택한 적이 있는지 여부.
- 명령의 과거 종료 상태. 이전에 실패한 명령은 실행하고 싶지 않을 것입니다.
bash를 사용 중이라면 mcfly를 설치한 뒤, ~/.bashrc
에 아래와 같은 내용을 추가합니다.
eval "$(mcfly init bash)"
재로그인하거나, 현재 세션에서 . ~/.bashrc
를 입력하여 사용합니다. ctrl
+ r
을 입력하면 mcfly
의 검색창이 독립된 화면으로 실행됩니다. 독립된 창에서 실행되는 것은 개인적으로 아쉬운 부분이네요.
[choose]
테이블 형태의 데이터를 다루기 위해 cut
이나 awk
를 많이 사용하시죠? 하지만 아쉬운 점들이 있는데요. cut
은 연속되어 있는 구분자를 다루지 못한다는 점이고, awk
는 태생적 한계로 인한 느린 속도와 긴 명령을 단점으로 꼽을 수 있겠습니다. choose
는 바로 이러한 두 도구의 가려운 부분을 해소해 줄 수 있는 도구입니다.
- 파이썬의 리스트 슬라이스와 유사한 간결한 필드 선택 구문
- 줄 끝에서 음수 인덱싱
- 선택적 시작/끝 인덱스
- 제로 인덱싱
- 역 범위
- 충분히 긴 입력의 경우
cut
보다 약간 빠르며,awk
보다 훨씬 빠름 - Rust의 정규식 구문을 사용하는 정규식 필드 구분 기호
choose 5 # print the 5th item from a line (zero indexed)
choose -f ':' 0 3 5 # print the 0th, 3rd, and 5th item from a line, where
# items are separated by ':' instead of whitespace
choose 2:5 # print everything from the 2nd to 5th item on the line,
# inclusive of the 5th
choose -x 2:5 # print everything from the 2nd to 5th item on the line,
# exclusive of the 5th
choose :3 # print the beginning of the line to the 3rd item
choose -x :3 # print the beginning of the line to the 3rd item,
# exclusive
choose 3: # print the third item to the end of the line
choose -1 # print the last item from a line
choose -3:-1 # print the last three items from a line
명령어가 살짝 길다는 단점이 있지만, 그래도 더 이상 cut
과 awk
사이에서 고민할 필요는 없겠네요.
[sd]
sd
는 sed
의 대체 도구입니다. sed
는 매우 강력하지만, 간단한 치환 작업을 하기 위해서도 항상 명령 구문을 지켜주어야 합니다. 구문이 복잡해질수록 뭘 하려는 건지 알아보기 힘들며, 가독성도 안 좋아지죠. 또한, 정규 표현식의 특수문자를 escape 하는 규칙도 직관적이지 않습니다. 그룹 캡처 특수 문자인 (...)
는 \(...\)
와 같이 escape 해야 하지만, 문자셋 특수 문자인 [...]
는 그대로 써야하며, 특정 횟수 반복 문자인 {...}
는 \{...\}
와 같이 써야 합니다. 익숙해지면 상관없겠지만, 일관적이지는 않다는 것을 알 수 있는데요. sed
의 간단한 버전인 sd
를 사용하면 이러한 고민을 할 필요가 없습니다.
- 간편한 정규식:
sd
는 JavaScript와 Python에서 이미 알고 있는 정규식 구문을 사용합니다. 이제sed
나 어색한 구문으로 고민할 필요 없이 즉시 생산성을 높일 수 있습니다. - 문자열 리터럴 모드: 비 정규식 찾기 및 바꾸기. 더 이상 백슬래시나 이스케이프 해야 하는 특수 문자를 기억할 필요가 없습니다.
- 읽기 쉽고 쓰기 쉬움: 찾기 및 바꾸기 표현식이 분할되어 있어 읽고 쓰기 쉽습니다. 더 이상 닫히지 않은 슬래시와 이스케이프 슬래시를 혼동하지 않아도 됩니다.
- 스마트하고 상식적인 기본값: 기본값은 상식을 따르며 일반적인 일상 사용에 맞게 조정되어 있습니다.
sed
는 훨씬 더 많은 일을 하지만, sd
는 한 가지 일을 잘하는 데 집중합니다.
sd
가 빛을 발하는 몇 가지 예시를 소개합니다:
- 모든 항목을 대체하는 더 간단한 구문:
– sd:sd before after
– sed:sed s/before/after/g
- 개행을 쉼표로 바꾸기:
– sd:sd '\n' ','
– sed:sed ':a;N;$!ba;s/\n/,/g'
- 슬래시가 포함된 문자열에서 내용 추출하기:
– sd:echo "sample with /path/" | sd '.*(/.*/)' '$1'
– sed: 표현식에 따라 매번 다른 구분 기호를 사용
*echo "sample with /path/" | sed -E 's/.*(\\/.*\\/)/\1/g'
*echo "sample with /path/" | sed -E 's|.*(/.*/)|\1|g'
- 파일을 제자리에서 수정하기:
– sd:sd before after file.txt
– sed:sed -i -e 's/before/after/g' file.txt
— 표현식에-e
를 사용하여-i
옵션의 백업 확장자로 인식하지 않도록 하기
[cheat]
특정 명령어가 낯설거나 사용법이 익숙치 않다면, 주로 --help
나 man
페이지로 옵션을 확인하죠. 하지만, 둘 다 실용적인 예제가 아니기 때문에 오히려 구글링을 먼저 하시는 분들도 많으실 것 같습니다. cheat
는 바로 이런 상황에서 사용하는 도구인데요. 자주 사용하는 명령어 형식만 추려서 보여주기 때문에, 사용법을 훨씬 쉽게 확인할 수 있습니다.
다만, cheat
에도 원하는 사용법이 나오지 않는다면, --help
나 man
페이지를 통해 사용법을 터득해야 합니다. 설명이 영어로 되어 있어, 조금 주의 깊게 읽어봐야 하는 점도 단점이긴 하지만, 어서 자국어화가 되어 한국인에게도 쓰기 편한 날이 오면 좋겠네요.
[bottom]
top
은 전체적인 시스템 상황을 한눈에 볼 수 있는 모니터링 도구입니다. 하지만 텍스트로만 이루어져 있어, 이상 상황을 한눈에 감지하기 어렵기도 합니다. 그래서 요즘 모니터링 도구들은 시각적인 효과를 조금 더 강조하는 추세입니다. 이쪽 계열에서 유명한 도구들로는 htop
, gtop
등이 있습니다. bottom도 이 중 하나인데요. 모니터링 도구로 한번 활용해 보는 것도 나쁘지 않을 것 같습니다. 명령어는 bottom이 아니라 btm
으로 입력합니다.
다음은 자주 사용하는 키 바인딩입니다.
?
: 도움말q
,ctrl
+c
: 프로그램 종료esc
: 취소f
: 업데이트 일시정지 / 재개e
: 선택된 위젯 확대 / 원래대로ctrl
+ 방향키,shift
+ 방향키,WASD
,HJKL
: 위젯 선택- 방향키,
hjkl
: 위젯 내 항목 선택
[procs]
위에서 소개해 드린 bottom
은 top
을 대체하기 위한 도구였죠. top
이 모니터링 도구라면, 특정 프로세스 정보를 자세히 보기 위한 명령으로는 ps
가 있습니다. procs
는 ps
에서 색상 출력 기능이 강화되고, 추가적인 정보를 제공하는 도구입니다. 또한 ps
와는 다르게 아무런 인자 없이 실행해도 모든 프로세스를 출력합니다.
- 인간 친화적인 컬러 출력
– 터미널 배경에 따른 자동 테마 감지 - 멀티-컬럼 키워드 검색
ps
에서는 지원하지 않는 몇 가지 추가 정보
– TCP/UDP 포트
– 읽기/쓰기 처리량
– docker 컨테이너 이름
– 추가 메모리 정보- pager 지원
- 감시 모드 (
top
과 같은) - 트리 보기
[zoxide]
마지막으로 소개해 드릴 도구는 zoxide입니다. 이름만 봐서는 어떤 명령을 대체하려고 하는지 감이 안 오는데요. 바로 cd
명령입니다. 이전에 McFly에서 보셨던 것과 같이 자주 이동하는 디렉터리나 최근에 이동했던 디렉터리를 기억하여 간단한 키워드 만으로도 디렉터리를 이동할 수 있습니다. 후보군에서 가려내기 위한 점수 계산은 frecency로 이루어진다고 하는데, frecency란 빈도(frequency), 최신성(recency)을 결합한 휴리스틱 지표 값으로 Mozilla Firefox 브라우저의 개발을 위해 만들어진 지표라고 합니다.
z foo # foo와 일치하는 가장 높은 순위의 디렉터리로 이동합니다.
z foo bar # foo와 bar가 일치하는 가장 높은 순위의 디렉터리로 이동합니다.
z foo / # foo로 시작하는 하위 디렉터리로 이동합니다.
z ~/foo # z도 일반 cd 명령처럼 작동합니다.
z foo/ # 상대 경로로 이동
z .. # 한 단계 위로 이동
z - # 이전 디렉터리로 이동
zi foo # 대화형 선택으로 cd (fzf 사용)
z foo<SPACE><TAB> # 대화형 자동완성 표시(zoxide v0.8.0+, bash 4.4+/fish/zsh만 해당)
zoxide는 간단하고 예측 가능한 알고리즘을 사용하여 쿼리를 해결합니다:
- 모든 일치는 대소문자를 구분하지 않습니다.
-z foo
는/foo
뿐만 아니라/FOO
와도 일치합니다. - 경로 내에 모든 용어(슬래시 포함)가 순서대로 존재해야 합니다.
-z fo ba
는/foo/bar
와 일치하지만/bar/foo
와는 일치하지 않습니다.
-z fo / ba
는/foo/bar
와 일치하지만/foobar
와는 일치하지 않습니다. - 마지막 키워드의 마지막 구성 요소는 경로의 마지막 구성 요소와 일치해야 합니다.
-z bar
는/foo/bar
와 일치하지만/bar/foo
와 일치하지 않습니다.
-z foo/bar
(마지막 구성 요소:bar
)는/foo/bar
와 일치하지만/foo/bar/baz
와는 일치하지 않습니다. - 일치 항목은 빈도 내림차순으로 반환됩니다.
[기타]
여기에 더 많은 도구들을 소개해 드리고 싶지만, 더 길어지면 루즈해질 것 같아 여러분들이 관심 있으실 만한, 다른 프로젝트들을 짧게 소개해 드리겠습니다.
— — —
[lsd]
아이콘을 지원하며, 설정 파일을 통해 다양한 커스터마이징이 가능한 ls
링크: https://github.com/Peltoche/lsd
— — —
[jq]
셸로 JSON을 자유자재로 다룰 수 있다고? JSON 데이터의 필수 도구
링크: https://github.com/stedolan/jq
— — —
[hyperfine]
단 하나의 느려짐도 용납할 수 없다! 커맨드라인 벤치마크 도구.
링크: https://github.com/sharkdp/hyperfine
— — —
[gping]
ping 응답 속도를 그래프로 확인해보자.
링크: https://github.com/orf/gping
— — —
[httpie]
curl
로 다양한 HTTP 요청을 보내는 것에 지쳤다면?
[마치며]
Part 1에 이어 Part 2도 소개해 드릴 수 있게 되어 좋았습니다.
여러분은 개발자에게 있어 가장 중요한 덕목이 무엇이라 생각하시나요?
물론 여러 가지 항목들이 있을 수 있겠지만, 제가 가장 중요하게 생각하는 것은 “불편한 것을 참지 못하는 자세”입니다.
이러한 도구들도 결국 기존의 Unix 도구들에서 느꼈던 불편한 점들을 개선하려는 프로젝트들이죠.
어느 누구도 불편을 느끼지 않는다면, 개선도 없고, 발전도 없을 것입니다.
이러한 컴퓨터 공학의 세계에서 여러분들이 느낀 불편을 개선하여 모두에게 공유해보는게 어떨까요?
정말 멋진 일인 것 같습니다.