[![Join the chat at https://gitter.im/jlevy/the-art-of-command-line](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jlevy/the-art-of-command-line?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
커맨드 라인을 능숙하게 다루는 것은 도외시되거나 신비스럽게 여겨집니다. 하지만 커맨드 라인은 명백하고도 미묘한 방법으로 엔지니어가 하는 작업의 유연성과 생산성을 향상시킵니다. 이 문서는 리눅스에서 작업을 하면서 찾은 노트와 팁들의 모음입니다. 몇 가지는 기초적이고, 몇 가지는 상당히 구체적이며, 세련되고, 잘 알려지지 않은 것입니다. 이 문서는 그리 길지 않지만, 여기 있는 모든 것을 사용할 수 있게 되고, 기억해낼 수 있게 된다면, 많은 것을 알게 되는 것입니다.
- 이 가이드는 초보자와 경험자 모두를 위한 것 입니다. 목표는 범위(전부 다 중요합니다!), 구체성(대부분의 일반적인 케이스에 대한 구체적인 예제), 그리고 간결함(쉽게 마주치지 않는, 중요하지 않고, 지엽적인 것을 피함)입니다. 모든 팁은 특정 상황에서 매우 중요하거나, 여러 대안들 사이에서의 시간을 확연하게 절약합니다.
- 이 문서는 리눅스를 위한것입니다. "[OS X only](#os-x-only)", "[Windows only](#windows-only)" 섹션을 제외하고 말이죠. 그 밖의 대부분은 유닉스, OS X(심지어 Cygwin)에서도 적용하거나 설치할 수 있습니다.
- 이 문서를 한 파일로 유지하기 위해서, 콘텐츠들은 암시적인 레퍼런스 형태로 포함되어있습니다. 한 개념이나 명령어에 대해 알게 된 후에, 구글에서 그에 대한 좀 더 자세한 정보를 찾을 수 있을 만큼 당신은 똑똑할 것입니다. `apt-get`, `yum`, `dnf`, `pacman`, `pip`, `brew` (혹은 적절한 다른 것)을 이용해 새 프로그램을 설치하세요.
- [Explainshell](http://explainshell.com/)을 이용해서 각각의 커맨드, 옵션, 파이프나 그 외 등등이 어떤 것인지 알아보십시오.
- 기본 Bash를 배우세요. 말하자면, 최소한 `man bash`를 실행하고, 전부를 훑어보세요. 매뉴얼의 내용은 따라가기 쉬우며 그리 길지 않습니다. 다른 쉘들 또한 좋습니다만, Bash는 강력하고 언제나 사용 가능합니다(zsh, fish, 그 외의 쉘*만*을 배우는 것은, 노트북에서는 좋겠지만, 많은 경우 제한이 생길 것입니다. 이미 존재하는 서버를 사용하는 것등의 일에서 말이죠).
-`man`을 이용해서 문서를 읽는 법을 배우세요(호기심 많은 사람을 위해서 하는 얘기입니다만, `man man`은 섹션 번호들의 목록을 표시합니다. 예를 들어 1은 "regular" 커맨드, 5는 files/conventions, 그리고 8은 administration이죠). `apropos`를 이용해서 man 페이지를 찾으세요. 몇몇 커맨드는 실행 가능한 커맨드가 아니라는 것을 알아두세요. 하지만 Bash 빌트인 함수들은 `help`와 `help -d`를 이용해서 도움말을 볼 수 있습니다.
- 기본 파일 관리: `ls`와 `ls -l`(특별히, `ls -l`에서 각각의 열이 무슨 의미인지 배우세요), `less`, `head`, `tail` 그리고 `tail -f`(또는 더 좋은 `less +F`), `ln`과 `ln -s`(하드 링크와 소프트 링크의 차이와 각각의 장단점을 배우세요), `chown`, `chmod`, `du`( 디스크 사용량의 빠른 요약을 보려면 `du -hs *`). 파일 시스템 관리를 위해서는 `df`, `mount`, `fdisk`, `mkfs`, `lsblk`. inode가 무엇인지 배우세요.(`ls -i` 또는 `df -i`)
-`apt-get`, `yum`, `dnf` 또는 `pacman`(배포판마다 다릅니다)을 이용하여 패키지를 찾고 설치하는 법을 배우세요. 그리고 `pip`가 설치되어 있는지 확인해서, 파이선 기반의 커맨드 라인 도구를 설치할 수 있도록 하세요(밑에 설명된 것 중 몇 가지는 `pip`를 이용해 설치하는 게 제일 쉽습니다.
- Bash 에서 **Tab**을 쓰면 argument를 완성하고, **ctrl-r**을 쓰면 커맨드 히스토리에서 검색합니다(누른 다음, 검색할 것을 입력하고, **ctrl-r**를 계속 눌러 좀 더 맞는 것을 찾을 수 있습니다. **Enter**를 눌러 찾은 커맨드를 실행하고 오른쪽 화살표 키를 눌러 결과를 현재 라인에 복사해 수정할 수 있습니다).
- Bash에서 **ctrl-w**는 마지막 단어를 지웁니다. **ctrl-u**는 라인의 처음까지 전부다 지웁니다. **alt-b**와 **alt-f**를 이용해서 단어 단위로 이동할 수 있습니다. **ctrl-a**로 라인의 시작점으로 이동할 수 있고 **ctrl-e**로 라인의 끝으로 이동할 수 있습니다. **ctrl-k**는 커서 위치부터 라인의 끝까지 지웁니다. **ctrl-l**은 화면을 깨끗하게 합니다. `man readline`을 이용해서 Bash의 기본 키 조합을 살펴보세요. 많은 것이 있습니다. 예를 들면 **alt-.**같은 경우, 이건 argument를 돌아가면서 나타내고 **alt-***는 글롭을 확장합니다.
- 최근 사용한 커맨드를 보려면 `history`를 입력하세요. 그 후 `!n`으로(여기서 `n`은 커맨드 번호를 뜻합니다) 다시 실행할 수 있습니다. `!$`(마지막 argument), `!!`(마지막 커맨드)와 같은 약어들이 매우 많습니다. 비록 이런 것들이 **ctrl-r**이나 **alt-.**명령어로 자주 대체되기 쉽지만요.
-`cd`로 홈 디렉터리로 갈 수 있습니다. 홈 디렉터리에서 상대적으로 파일을 접근하려면 `~` 접두사를 사용합니다(예: `~/.bashrc`). `sh` 스크립트에서는 `$HOME`로 홈 디렉터리를 참조합니다.
- 이전에 작업하던 디렉터리로 돌아가려면 `cd -`를 사용하세요.
- 커맨드를 타이핑하던 도중에 마음이 바뀌었다면, **alt-#**을 쳐서 시작점에 `#`을 삽입하고, 엔터를 쳐서 코멘트로 여겨지게 하세요(또는 **ctrl-a**, **#**, **enter**). 나중에 커맨드 히스토리에서 찾아서 타이핑 중이었던 커맨드로 돌아올 수 있습니다.
-`xargs`(혹은 `parallel`)를 사용하세요. 매우 강력합니다. 라인당 몇 개의 아이템이 실행되게 할 것인지(`-L`) 그걸 병렬로 할 것인지(`-P`)를 제어할 수 있다는 걸 기억하세요. 제대로 하고 있는지 확신할 수 없다면 `xargs echo`를 먼저 실행해보세요. 또 `-I{}`도 편리합니다. 예시:
- Git으로 여러 컴퓨터에서 같은 설정 파일을 사용하세요(예 `.bashrc`, `.bash_profile`).
- 공백이 들어간 변수명이나 파일명은 주의할 필요가 있습니다. Bash 변수를 따옴표로 감싸세요(예: `"$FOO"`). 파일 이름의 경계에 공백 문자를 허용하려면 `-0`이나 `-print0` 옵션을 사용하세요. 예를 들면, `locate -0 pattern | xargs -0 ls -al`, `find / -print0 -type d | xargs -0 ls -al`. for 문에서 공백문자가 포함된 파일 이름을 반복하려면, `IFS=$'\n'`로 IFS를 개행 문자만으로 설정하시면 됩니다.
- Bash스크립트에서 `set -x`를 사용하면 디버깅용 출력을 사용하게 됩니다(아니면 다른 옵션 `set -v`가 있습니다. 확장되지 않은 변수와 주석을 포함한 로우 입력을 로깅합니다). 스트릭트 모드(strict mode)가 가능할 때면 사용하세요. `set -e`를 사용하면 에러가 났을 때 중단시키게 됩니다. `set -u`을 사용하면 설정되지 않은 변수를 찾아 줍니다. `set -o pipefail`을 사용하면 에러에 대해서 강경한 기준을 적용합니다(이 주제가 조금 미묘하지만 말이죠). 더 복잡한 스크립트의 경우 EXIT나 ERR에 `trap`도 사용합니다. 이렇게 스크립트를 시작하는 습관은 유용합니다. 이렇게 하면, 일반적인 에러를 찾고 중단하고, 메시지를 출력해 줍니다.
```bash
set -euo pipefail
trap "echo 'error: Script failed: see failed command above'" ERR
```
- Bash 스크립트에서 (괄호로 둘러싸여 작성된) 서브 셸은 커맨드를 그룹으로 묶는 편리한 방법입니다. 일반적인 예로, 임시로 다른 디렉터리로 이동하여 작업하는 것이 있습니다.
- Bash 에는 다양한 변수 확장이 있다는 것을 알아두세요. 변수가 존재하는지 확인하려면 `${name:?error message}`를 사용하세요. 예를 들어 Bash 스크립트가 하나의 argument를 요구한다면, `input_file=${1:?usage: $0 input_file}`를 사용하세요. 변수가 비어있을 때를 대비해 기본 값을 사용하세요. `${name:-default}` 이전 예제에 선택적인 파라미터를 추가하길 원한다면 `output_file=${2:-logfile}`로 할 수 있습니다. $2가 생략되어 비어있다면, `output_file`은 `logfile`로 설정됩니다. 산술 확장은 `i=$(( (i + 1) % 5 ))` 처럼 사용합니다. 순열은 `{1...10}`처럼 사용합니다. 문자열 트리밍(trimmin)은 `${var%suffix}`이나 `${var#prefix}`처럼 사용할 수 있습니다. 예를 들어 `var=foo.pdf`라면, `echo ${var$.pdf}.txt`는 `foo.txt`를 출력합니다.
- Bash에서 표준 출력(standard output)과 표준 에러(standard error) 둘 다 `some-command > logfile 2>&1`같은 명령어로 리다이렉트할 수 있습니다. 종종, 커맨드가 열린 파일 핸들을 남기지 않는 것을 확실히 하기 위해, 현재 작업 중인 터미널에서 명령어에 `</dev/null`을 덧붙이는 것은 좋은 습관입니다.
-`screen`을 이용하거나 [`tmux`](https://tmux.github.io/)를 이용해서 화면을 다중 분할할 수 있습니다. 특히 리모트 ssh 세션을 떼어내고(detach) 다시 붙이는데(re-attach) 유용합니다. `byobu`은 스크린이나 tmux보다 더 많은 정보를 제공하며, 관리를 편합니다. 세션을 영구히 유지하는 최소한의 대안은 오직 [`dtach`](https://github.com/bogner/dtach)밖에 없습니다.
- 몇 가지 ssh 설정을 최적화하는 것은 유용할 수 있습니다. 예를 들어 `~/.ssh/config`는 특정 네트워크 환경에서 연결이 끊기는 것을 회피하기 위해 압축을 사용하는 설정들을 담고 있습니다(특히 scp 명령어를 낮은 대역폭 연결에서 사용하는 경우에 도움이 됩니다. 그리고 로컬 제어 파일에서 같은 서버로 연결하는 채널을 다중화할 수 있습니다.
- 권한을 가지고 커맨드를 실행하려면, `sudo`를 사용하세요. 기본값은 root 실행하며 `sudo -u`로 다른 유저를 지정할 수 있습니다. `-i`를 이용해 다른 사람으로 로그인 할 수 있습니다.(_당신의_ 패스워드를 물어볼 것입니다)
- 셸을 다른 유저로 전환하려면 `su username`나 `su - username`를 사용하세요. `-`를 넣으면 그 유저가 방금 로그인한 것 같은 환경을 얻을 수 있습니다. 유저 이름을 생략하면 기본값은 root가 됩니다. _당신이 전환하려하는 유저의_ 비밀번호를 물어볼 것입니다.
- 커맨드 라인의 [128K 제한](https://wiki.debian.org/CommonErrorMessages/ArgumentListTooLong)을 알아 두세요. "Argument list too long" 에러는 많은 파일을 와일드카드 매칭할 때 일반적으로 일어납니다. (이런 일이 일어났을 때에는 `find`, `xargs`같은 것이 도움 됩니다.)
- 단순한 계산에는(물론 일반적으로는 Python에 접근하기 위해) `python` 인터프리터를 사용하세요. 예를 들어 이렇게 사용할 수 있습니다.
- 현재 디렉터리에서 파일을 이름으로 찾으려면 `find . -iname '*something*'` (또는 비슷하게)를 사용하면 됩니다. 어느 곳에 있든 파일을 이름으로 찾으려면 `locate something`을 사용하세요(하지만 인내를 가져야 합니다. `updatedb`가 최근에 생성된 파일을 인덱싱하지 않았을 수 있습니다).
- Amazon S3를 다룰 때는 [`s3cmd`](https://github.com/s3tools/s3cmd)가 편리합니다. 그리고 [`s4cmd`](https://github.com/bloomreach/s4cmd)는 빠릅니다. Amazon의 [`aws`](https://github.com/aws/aws-cli)는 다른 AWS 관련 작업에 핵심적인 도구입니다.
- 로케일이 커맨드 라인 도구에 정렬 순서(collation)와 퍼포먼스를 포함해서 미묘하게 영향을 끼치는 것을 알아두세요. 대부분의 리눅스 설치는 `LANG`이나 다른 로케일 변수를 US English와 같은 로컬 세팅으로 설정합니다. 하지만 로케일을 바꿀 경우 정렬도 바뀔 것이라는 것에 주의하세요. 그리고 i18n 루틴들도 정렬이나 다른 커맨드들을 *몇 배* 느리게 할 수 있습니다. `export LC_ALL=C`를 사용하여, 어떤 상황에서는( 밑에 있는 집합(set) 작업이나, 유일성 작업등) i18n의 느린 루틴들을 통째로 안전하게 무시할 수 있습니다. 그리고 전통적인 바이트 기반의 정렬 순서를 사용할 수 있습니다.
- 간단한 데이터 조작을 할 때 `awk`와 `sed`를 이용하는 것을 알아두세요. 예를 들어 텍스트 파일의 세 번째 열의 숫자들의 모든 값을 더하는 것은 이렇게 합니다: `awk '{ x += $3 } END { print x }'`. 이 방법은 같은 일을 하는 파이썬 코드보다 3배 정도 빠르고, 1/3 정도의 길이밖에 안됩니다.
- 여러 파일의 이름을 바꾸거나 검색하거나 문자열을 바꿀 때에는 [`repren`](https://github.com/jlevy/repren)를 써보세요. (어떤 경우에는 `rename` 명령을 사용해서 여러 파일의 이름을 바꿀 수도 있습니다. 하지만, 모든 리눅스 배포판에서 같은 동작을 하지 않는 것에 주의하세요.)
- man 페이지가 이야기하듯, `rsync`는 정말 빠르고 다재다능한 파일 복사 도구입니다. 기기 간의 동기화에 사용하는 것으로 알려져 있지만, 로컬에서도 충분히 유용합니다. 보안 규정이 허용한다면, `scp` 대신 `rsync`를 사용하면 처음부터 전송하는 대신 중단된 지점부터 재전송할 수 있습니다. 또 많은 수의 파일을 삭제하는 [가장 빠른 방법](https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html)이기도 합니다.
-`sort`의 옵션을 알아두세요. `-n`은 숫자를 정렬할 때, `-h`는 사람이 읽을 수 있게 작성한 숫자의 경우(`du -h`와 같은 형태). 키가 어떻게 작동하는지 알아두세요(`-t`와 `-k`). 특별히, 첫 번째 필드로만 정렬해야 한다면 `-k1,1`을 적어야 한다는 걸 주의하세요. `-k1`은 모든 행에 대해서 정렬하라는 뜻입니다. 안정적인 정렬(`sort -s`)도 유용합니다. 예를 들어, 먼저 2번 필드로 정렬하고, 그다음에 1번 필드로 정렬할 경우, `sort -k1,1 | sort -s -k2,2`처럼 할 수 있습니다.
- 소스 코드를 패치하는 기본 도구는 `diff`와 `patch`입니다. diff와 `sdiff`(새로 diff)의 통계 요약을 보려면 `diffstat`를 보세요. `diff -r`은 모든 디렉터리에 대해 작업을 수행하는 걸 알아두세요. `diff -r tree1 tree2 | diffstat`으로 변경 내역의 요약을 볼 수 있습니다.
- 텍스트 파일 인코딩을 변경하려면 `iconv`를 시도해보세요. 또는 `uconv`는 더 복잡한 목적에 사용할 수 있습니다. `uconv`는 몇 가지 복잡한 유니코드를 지원합니다. 예를 들어, 소문자화하고 모든 악센트를 제거하는(확장하고, 떨어트리는 것을 이용해서) 커맨드는 다음과 같습니다.
- 메모리의 상태를 알아보려면 `free` 와 `vmstat`를 실행하고 그 결과를 해석해보세요. 특히, "cached" 값은 Linux kernel에 의해 file cache로 잡혀있는 메모리 라는 것을 알고 있어야 하고 그래서 "free"값에 대해서 보다 효율적으로 계산할 수 있습니다.
- Java 시스템의 디버깅은 조금 다른 상황입니다. 하지만 Oracle과 그 외의 회사에서 만든 다른 JVM들에서는 `kill -3 <pid>`를 실행하면 전체 stack trace 정보와 heap의 정보(시기별로 가비지 컬렉터의 세부적인 내용 같은 매우 유용한 정보)를 요약하여 stderr나 로그로 출력해주므로 간단하게 정보를 얻어올 수 있습니다. JDK의 `jps`, `jstat`, `jstack`, `jmap` 명령은 유용합니다. [SJK tools](https://github.com/aragozin/jvm-tools)은 더 고급 정보를 다룰 수 있습니다.
- 보다 심각한 경우의 네트워크 디버깅을 위해서는 [`wireshark`](https://wireshark.org/), [`tshark`](https://www.wireshark.org/docs/wsug_html_chunked/AppToolstshark.html), [`ngrep`](http://ngrep.sourceforge.net/)를 사용하세요.
-`strace` 와 `ltrace`에 대해서 알아보세요. 이 커맨드들은 만일 어떤 프로그램에서 failing, hanging 혹은 crashing이 일어나거나 그 외에 여러분이 무슨 이유인지 알지 못하는 상황이나 성능에 대한 대략적인 내용을 얻고자 할 때 유용할 것입니다. 특히 프로파일링을 위한 옵션(`-c`)과 현재 실행 중인 프로세스에 붙이기 위한 옵션(`-p`)을 기억하세요.
-`/proc`를 사용하세요. 이것은 현재 발생하고 있는 문제를 디버깅할 때 종종 놀랍도록 큰 도움이 될 것입니다. 예시:`/proc/cpuinfo`, `/proc/meminfo`, `/proc/cmdline`, `/proc/xxx/cwd`, `/proc/xxx/exe`, `/proc/xxx/fd/`, `/proc/xxx/smaps` (`xxx`는 프로세스 id나 pid입니다).
- 시스템의 보다 깊은 곳을 보거나 퍼포먼스를 분석하기 위해서는, `stap` ([SystemTap](https://sourceware.org/systemtap/wiki)), [`perf`](http://en.wikipedia.org/wiki/Perf_(Linux)), [`sysdig`](https://github.com/draios/sysdig)를 사용해보세요.
-`sort`/`uniq`를 사용하여 텍스트 파일의 교차점, 조합, 차이점을 확인이 필요할 때 상당한 도움이 될 겁니다. 가령 `a`와 `b`가 유일한 값들만을 가진 텍스트 파일이라 합시다. 이것이 임의의 크기인 파일을(그게 기가바이트라고 해도) 빠르게 작업할 수 있습니다. (Sort는 메모리 제한에 걸리지 않습니다만, 만약 루트 파티션이 작은 경우, `/tmp`를 사용하기 위해 `-T`옵션을 사용하면 됩니다.) 위의 `LC_ALL`에대한 내용은 `sort`의 `-u`옵션을 확인하십시오. (아래 예제에 집중하기 위해서 생략)
-`grep . *`을 사용해서 디렉터리 안의 모든 파일을 비주얼하게 살펴볼 수 있습니다.(r각 줄은 파일 이름과 같이 나옵니다) 아니면 `head -100 *`를 이용할 수도 있습니다.(각 파일의 해더만 볼 수 있습니다.) 이는 `/sys`, `/proc`, `/etc` 같이 설정값들로 가득한 디렉터리에서 유용합니다.
- 변경을 계속 모니터링하려면 `watch`를 이용하세요. 예를 들어 `watch -d -n 2 'ls -rtlh | tail'`로 한 디렉터리 내의 파일 변경을 확인하거나, `watch -d -n 2 ifconfig`로 와이파이 설정을 고칠 때 네트워크 설정 변경을 확인할 수 있습니다.
- OS X는 BSD Unix 기반이며 많은 명령어들을 (예로 `ps`, `ls`, `tail`, `awk`, `sed`) 사용할 수 있으며, 이것들은 Linux 버전들과 미묘한 차이가 있습니다. 그리고 크게는 System V-style Unix와 GNU 도구들에 많은 영향을 받았습니다. 이런 내용들을 man 페이지 상단의 "BSD General Commands Manual." 라는 문구를 통해 알 수 있습니다. 가끔은 GNU 버전이 설치되기도 합니다. (예로, GNU awk와 sed인 `gawk`와 `gsed`에서). 만약 이종 플랫폼 간 Bash 스크립트를 작성하려면, 동일한 명령어 (예로, 파이썬이나 `perl`과 같은)나 테스트시 주의해야 합니다.
- OS X 릴리스 정보를 얻으시려면, `sw_vers`를 사용하세요.
## Windows only
Windows*에서만* 해당되는 항목입니다.
- Windows 10에서는 [Bash on Ubuntu on Windows](https://msdn.microsoft.com/commandline/wsl/about)를 사용할 수 있습니다. 이는 유닉스 커맨드 라인 도구와 함께 친숙한 Bash 환경을 제공합니다. 좋은 점은, 리눅스 프로그램을 Windows에서 사용할 수있게 합니다. 하지만 Bash에서 Windows 프로그램을 사용할 수는 없습니다.
- [Cygwin](https://cygwin.com/)를 설치해 Microsoft Windows에서 유닉스 셸을 사용할 수 있습니다. 이 문서에 기술된 대부분의 것들은 그대로 동작할 것입니다.
- Cygwin의 패키지 매니저로 유닉스 프로그램을 더 설치할 수 있습니다.
- 커맨드 라인 창으로 `mintty`를 사용하세요.
- Windows의 클립보드를 `/dev/clipboard`로 접근할 수 있습니다.
-`cygstart`을 실행해 등록된 애플리케이션을 사용해 임의의 파일을 열 수 있습니다.
- Windows 레지스트리는 `regtool`로 접근할 수 있습니다.
-`C:\\` Windows 드라이브 경로는 Cygwin에서는 `/cygdrive/c`가 되고, Cygwin의 `/` Windows에서 `C:\cygwin`가 되는것을 알아 두세요. Cygwin과 Windows 스타일의 파일 패스는 `cygpath`로 변환할 수 있습니다. 이는 Windows 프로그램을 실행하는 프로그램에서 유용하게 사용됩니다.
- You can perform and script most Windows system administration tasks from the command line by learning and using `wmic`.
- Windows에서 유닉스 룩엔필을 얻는 다른 대안은 [Cash](https://github.com/dthree/cash)입니다. 이 환경에는 매우 적은 유닉스 명령과 커맨드 라인 옵션만 사용가능하니 주의하세요.
- Windows에서 GNU 개발자 툴(GCC같은)을 얻는 다른 대안으로 [MinGW](http://www.mingw.org/)와 거기에 포함된 [MSYS](http://www.mingw.org/wiki/msys) 패키지가 있습니다. 여기에는 bash, gawk, make, grep같은 도구가 포함됩니다. MSYS는 Cygwin에 비교하면 모든 기능은 없습니다. MinGW는 유닉스 툴을 네이티브 Windows로 포팅할 때 부분적으로 유용합니다.