·터미널 명령어

터미널 명령어 사전

파일·텍스트·git·프로세스·네트워크까지, 옵션과 예시를 함께 보는 명령어 227가지

⌨️ 명령과 옵션은 그대로 치는 것이라 번역하지 않습니다. 설명만 언어를 따릅니다.

파일·디렉터리32

옮기고 지우고 찾는 것들. 되돌릴 수 없는 명령이 섞여 있어 -i를 붙이는 습관이 손을 구합니다.

ls디렉터리에 무엇이 있는지 보여줍니다. 점으로 시작하는 이름은 -a를 붙일 때까지 숨어 있습니다.cd셸의 현재 디렉터리를 옮깁니다. 셸 내장 명령이라 스크립트나 서브셸 안에서 한 cd는 바깥 셸을 움직이지 않습니다.pwd지금 서 있는 디렉터리를 찍습니다. 심볼릭 링크로 들어왔다면 기본은 링크 쪽 경로이고, 실제 경로는 -P만 보여 줍니다.mkdir디렉터리를 만듭니다. -p가 없으면 상위 디렉터리가 없을 때도, 이미 있을 때도 오류로 멈춥니다.rmdir빈 디렉터리만 지웁니다. 안에 무엇이든 있으면 거절하니, 그래서 사람들이 rm -r로 갑니다.rm파일을 되돌릴 수 없게 지웁니다. 휴지통이 없고, rm -rf에 빈칸 하나가 잘못 들어가면 엉뚱한 것이 사라집니다.cp파일이나 디렉터리를 복사합니다. 목적지가 이미 있느냐에 따라 원본이 그 이름이 되기도 하고 그 안에 들어가기도 합니다.mv이름을 바꾸거나 옮깁니다. -i나 -n이 없으면 목적지 파일을 묻지 않고 덮어씁니다.touch파일의 시각을 지금으로 올리고, 없으면 빈 파일로 만듭니다. 내용은 결코 건드리지 않습니다.cat파일을 이어서 그대로 찍습니다. 한 번에 다 뿌리니 긴 파일은 less가 맞고, cat file | grep은 파이프 하나가 군더더기입니다.less파일을 통째로 읽지 않고 한 화면씩 보여줍니다. /로 찾고 q로 나오는데, more처럼 끝에서 저절로 닫히지 않습니다.head파일의 앞부분을 찍습니다. 파일 여럿을 주면 -q를 붙이지 않는 한 파일마다 제목 줄이 끼어듭니다.tail파일의 끝을 찍고 -f로 계속 지켜봅니다. 로그가 돌아간 뒤에도 따라가려면 -F여야 합니다.find디렉터리를 훑으며 하나하나 조건에 대 봅니다. -name '*.log'처럼 따옴표를 씌우지 않으면 셸이 먼저 펼쳐 버립니다.locate미리 만들어 둔 색인을 뒤지니 즉시 나오지만, 마지막 updatedb 뒤에 생긴 파일은 보지 못합니다.tree디렉터리 구조를 들여쓴 그림으로 그립니다. macOS와 가벼운 리눅스 이미지에는 기본으로 없어 먼저 설치해야 합니다.du파일이 실제로 차지한 디스크 공간을 더합니다. 블록으로 세기 때문에 파일 크기의 합이나 df의 값과 어긋납니다.df파일시스템마다 쓴 공간과 남은 공간을 알려 줍니다. 바이트가 남았는데 inode가 다 차서 쓰기가 막힐 수 있고, 그것은 df -i만 보여 줍니다.ln파일에 다른 이름을 붙입니다. -s로 만든 심볼릭 링크는 어디든 가리킬 수 있지만 대상이 옮겨지면 끊기고, 상대 경로는 링크가 놓인 자리에서 읽습니다.statinode에 적힌 것을 그대로 보여 줍니다 — 크기, 권한, 소유자와 세 가지 시각. 서식 옵션이 GNU는 -c, BSD는 -f인데 GNU에서 -f는 뜻이 아예 다릅니다.file이름이 아니라 내용을 보고 파일 종류를 알아냅니다. 확장자를 무시하니 .jpg인데 실은 PDF인 것이 여기서 드러납니다.basename경로에서 디렉터리 부분을 떼고 원하면 확장자까지 잘라 냅니다. 문자열만 다루므로 그 파일이 있는지는 보지 않습니다.dirname경로의 디렉터리 부분만 남깁니다. 슬래시가 없으면 점 하나를 찍고, basename처럼 문자열만 봅니다.realpath어떤 경로든 심볼릭 링크와 점을 다 풀어 절대 경로 하나로 만듭니다. macOS의 것은 BSD판이라 --relative-to 같은 GNU 옵션이 없습니다.rsync두 디렉터리의 다른 점만 옮깁니다. 원본 끝에 슬래시를 붙이면 그 안의 것을 뜻하고, 빼면 디렉터리가 한 겹 더 깊이 들어갑니다.mount파일시스템을 디렉터리에 붙입니다. 붙이는 자리에 원래 있던 것은 지워지지 않고 가려질 뿐이라, 떼면 다시 나옵니다.umount붙여 둔 파일시스템을 뗍니다. 이름에 n이 없고, 그 안에 열린 파일이나 셸의 현재 위치가 남아 있으면 busy라며 거절합니다.readlink심볼릭 링크가 무엇을 가리키는지 한 단계만 찍습니다. -f를 붙이면 끝까지 따라가고, 링크가 아닌 파일에는 아무것도 찍지 않고 실패로 끝납니다.mktemp아무도 맞힐 수 없는 이름으로 임시 파일이나 디렉터리를 만들고 그 경로를 찍습니다. 스스로 지우지는 않으니 종료 때 지우는 trap과 함께 씁니다.sha256sum파일의 SHA-256 지문을 찍어 내려받은 것이 온전한지 대조하게 합니다. 값이 같다는 것은 바이트가 같다는 뜻일 뿐, 그 출처를 믿을 수 있다는 뜻은 아닙니다.truncate파일 길이를 딱 그 크기로 맞춥니다. 늘릴 때는 구멍만 뚫어 공간을 잡지 않고, 줄일 때는 잘려 나간 뒤쪽을 경고 없이 버립니다.shred지우기 전에 그 자리를 덧써서 되살리기 어렵게 합니다. 다만 SSD와 btrfs, APFS처럼 쓰는 자리가 옮겨 다니는 저장소에서는 옛 블록이 남을 수 있어, 결국은 디스크 암호화가 답입니다.

텍스트 처리32

파이프로 이어 쓰는 것이 본래 용도입니다. 한 명령이 다 하는 것보다 셋을 잇는 편이 짧습니다.

grep글에서 무늬에 맞는 줄을 골라냅니다. 기본이 기초 정규식이라 + ? | 와 () 는 -E를 붙이거나 역슬래시를 씌워야 뜻이 삽니다.sed줄 단위로 글을 고칩니다. 자리에서 고치는 -i가 GNU와 BSD에서 다르고, 끝에 g가 없으면 줄마다 첫 번째만 바뀝니다.awk줄을 칸으로 쪼개어 작은 프로그램을 돌립니다. $0은 줄 전체, $1이 첫 칸이고, 기본 구분자는 빈칸 하나가 아니라 연이은 공백입니다.sort줄을 정렬합니다. -n이 없으면 글자로 견주어 10이 9보다 앞서고, 순서는 로케일이 정하므로 LC_ALL=C를 앞에 두면 고정됩니다.uniq잇달아 같은 줄만 하나로 줄입니다. 떨어져 있는 중복은 보지 못하므로 거의 항상 sort 뒤에 씁니다.wc줄과 낱말, 바이트를 셉니다. -l은 줄바꿈 문자를 세는 것이라 마지막 줄에 줄바꿈이 없으면 그 줄은 셈에서 빠집니다.cut정해진 칸이나 글자 자리를 잘라 냅니다. 구분자는 글자 하나이고 연이은 구분자를 하나로 합치지 않으니, 공백으로 맞춰진 표는 awk가 낫습니다.paste파일들을 나란히 붙여 칸으로 만듭니다. join과 달리 내용을 보지 않고 줄 순서만으로 맞춥니다.tr글자를 하나하나 바꾸거나 지웁니다. 표준 입력만 읽으므로 파일 이름을 그냥 붙이면 안 되고 < 나 파이프로 넣어야 합니다.join두 파일을 공통 칸으로 이어 붙입니다. 데이터베이스의 join과 같지만, 두 파일이 그 칸으로 미리 정렬돼 있지 않으면 줄이 조용히 빠집니다.comm정렬된 두 파일을 견주어 왼쪽만, 오른쪽만, 둘 다를 세 칸으로 보여 줍니다. 정렬이 안 돼 있으면 결과가 엉뚱하고, 옵션은 칸을 고르는 것이 아니라 숨기는 것입니다.diff두 파일이 어디가 달라졌는지 보여 줍니다. patch와 코드 리뷰가 기대하는 꼴은 -u이고, 다르면 종료 코드가 1이라 set -e를 쓴 스크립트가 여기서 멈춥니다.patchdiff를 파일에 실제로 적용합니다. -p가 패치에 적힌 경로를 몇 겹 버릴지 정하고, git 패치는 a/ b/ 접두사 때문에 -p1이 필요합니다.tee들어온 것을 파일에도 쓰고 화면에도 그대로 흘립니다. root 소유 파일에 쓰려면 이것이 답인데, sudo cmd > file의 > 는 내 셸이 열기 때문입니다.xargs들어온 줄을 다른 명령의 인수로 바꿔 넘깁니다. 이름에 빈칸이 있으면 깨지므로 find -print0과 xargs -0을 짝지어야 합니다.echo인수를 그대로 찍고 줄을 바꿉니다. -e와 역슬래시 처리가 셸마다 달라, 확실하게 하려면 printf를 씁니다.printfC의 printf처럼 서식에 맞춰 글을 만듭니다. 줄바꿈을 스스로 붙이지 않고, 인수가 남으면 서식을 처음부터 다시 씁니다.jqJSON을 제 나름의 작은 언어로 걸러 모양을 바꿉니다. 기본으로 깔려 있지 않은 경우가 많고, 문자열의 따옴표를 벗기려면 -r이 있어야 합니다.column칸을 채워 줄을 맞춰 표처럼 보이게 합니다. 연이은 구분자를 하나로 합쳐 버리므로 빈 칸이 있는 CSV는 한 칸씩 밀립니다.fold긴 줄을 정해진 너비에서 잘라 진짜 줄바꿈을 넣습니다. -s가 없으면 낱말 가운데를 자르고, 터미널의 화면 접힘과 달리 파일 내용이 바뀝니다.nl찍으면서 줄 번호를 붙입니다. 기본이 빈 줄을 세지 않아 편집기의 줄 번호와 어긋나는데, -b a를 주면 맞습니다.rev줄마다 글자 순서를 거꾸로 돌립니다. 줄의 순서를 뒤집는 것은 tac이고, 이것은 한 줄 안의 글자입니다.split파일을 여러 조각으로 자릅니다. 머리글 줄은 첫 조각에만 남고, 이름은 -d를 주지 않으면 aa, ab처럼 글자로 붙습니다.csplit크기가 아니라 무늬가 나타나는 자리에서 파일을 자릅니다. 찍히는 숫자는 조각의 바이트 수이고, {*}는 맞는 만큼 되풀이하라는 뜻입니다.expand탭을 빈칸으로 바꿉니다. Makefile은 진짜 탭이 있어야 돌아가므로, 거기에 이것을 돌리면 빌드가 깨집니다.shuf줄을 무작위 순서로 내놓습니다. GNU coreutils라 macOS에는 없고, 대신 쓰는 sort -R은 같은 줄을 한데 묶어 버립니다.tac파일의 줄을 마지막부터 거꾸로 찍습니다. GNU coreutils라 macOS에서는 tail -r을 쓰고, 글자를 뒤집는 rev와는 다릅니다.strings이진 파일에서 글자처럼 보이는 것을 뽑아냅니다. 글자로 보이면 다 건지므로 대부분은 뜻이 아니라 우연입니다.iconv글의 문자 인코딩을 다른 것으로 바꿉니다. 옮길 수 없는 바이트를 만나면 -c가 없는 한 그 자리에서 멈추고, 원래 인코딩을 스스로 알아내지는 못합니다.vim모드가 있는 편집기라 그냥 치면 아무것도 들어가지 않습니다. i로 입력을 시작하고, Esc로 나온 뒤 :wq로 저장하거나 :q!로 버립니다.nano화면 아래에 명령이 적혀 있는 단순한 편집기입니다. ^O와 ^X의 캐럿은 글자가 아니라 Ctrl을 뜻합니다.base64바이트를 ASCII 글자로, 또 되돌려 바꿉니다. 암호가 아니라 표기법일 뿐이고, 되돌리는 옵션이 GNU는 -d, 옛 macOS는 -D입니다.

git45

되돌리는 방법이 여럿이라 헷갈립니다 — 가리키는 곳을 옮기는 것과 새 커밋을 얹는 것은 다릅니다.

git init폴더 하나를 새 git 저장소로 만듭니다 — init만으로는 아무 파일도 추적되지 않아 add와 commit이 따로 필요합니다.git clone원격 저장소를 이력째 복사해 옵니다 — --depth 1로 얕게 받으면 옛 커밋과 다른 브랜치가 없어 나중에 --unshallow가 필요합니다.git configgit의 설정을 읽고 씁니다 — --global을 빼면 지금 저장소에만 적혀서 새로 클론한 곳은 그 설정을 모릅니다.git init --bare작업 폴더가 없는 저장소를 만듭니다 — 받아만 두는 곳이라 안의 파일을 고칠 수 없지만, 체크아웃된 브랜치로 밀어 넣다 거절당하는 일도 없습니다.git add지금 파일 상태를 커밋 대기 자리에 올립니다 — 올린 뒤 또 고치면 그 수정은 담기지 않아 다시 add해야 합니다.git commit스테이지에 올린 것만 한 덩어리로 기록합니다 — -a는 추적 중인 파일만 담아 새로 만든 파일은 빠집니다.git status무엇이 스테이지에 있고 무엇이 아직 아닌지 보여줍니다 — 추적되지 않은 파일은 폴더 이름으로 뭉쳐 나오니 낱낱이 보려면 -uall을 붙입니다.git diff아직 스테이지에 올리지 않은 수정만 보여줍니다 — add한 뒤에는 비어 보이니 그때는 --staged로 봅니다.git log커밋 이력을 새것부터 보여줍니다 — 지금 HEAD의 조상만 나오니 다른 브랜치까지 보려면 --all이 필요합니다.git show커밋 하나의 메시지와 변경을 펼쳐 보여줍니다 — <commit>:<path> 꼴로 적으면 작업 파일을 건드리지 않고 옛 내용만 꺼내 볼 수 있습니다.git blame한 줄 한 줄 마지막으로 고친 커밋을 붙여 보여줍니다 — 서식만 바꾼 커밋이 진짜 저자를 가리므로 -w와 --ignore-rev가 있습니다.git branch브랜치를 나열하고 만들고 지웁니다 — 지워도 원격에는 그대로 남아 서버에서 없애려면 git push origin --delete가 따로 필요합니다.git checkout브랜치를 옮기고 파일도 되돌리는 옛 명령으로, git 2.23에서 switch와 restore로 갈라졌습니다 — checkout -- <file>은 커밋하지 않은 수정을 되찾을 수 없게 지웁니다.git switch브랜치를 옮기는 일만 하는 git 2.23의 명령입니다 — 파일 내용을 되돌리는 일은 하지 않으니 그건 restore가 맡습니다.git restore파일 내용을 되돌리는 git 2.23의 명령입니다 — 기본값은 작업 파일을 덮어써 커밋하지 않은 수정이 사라지고, --staged는 스테이지에서만 내립니다.git merge다른 브랜치의 작업을 지금 브랜치로 합칩니다 — --squash는 합침 기록을 남기지 않아 그 브랜치가 나중에도 합쳐지지 않은 것으로 보입니다.git rebase내 커밋을 다른 기준 위에 다시 얹습니다 — 해시가 새로 생기므로 남이 이미 받아 간 브랜치에는 rebase하지 않고 merge를 씁니다.git reset브랜치가 가리키는 커밋을 옮깁니다 — --soft는 변경을 스테이지에 남기고, --mixed(기본)는 스테이지만 풀어 수정은 파일에 두며, --hard는 파일의 수정까지 함께 버려 되찾을 수 없습니다.git revert되돌리는 변경을 새 커밋으로 덧붙입니다 — 이력을 지우지 않는다는 점이 포인터를 옮기는 reset과의 차이라, 이미 올린 커밋은 revert로 되돌립니다.git cherry-pick다른 브랜치의 커밋 하나를 지금 브랜치에 복사합니다 — 해시가 새로 생기므로 나중에 그 브랜치를 merge하면 같은 변경이 두 번 보일 수 있습니다.git stash고치던 것을 잠시 치워 두고 깨끗한 상태로 돌아갑니다 — 기본으로는 추적되지 않은 파일이 그대로 남으니 -u를 붙이고, pop은 꺼내면서 목록에서 지우고 apply는 남깁니다.git clean추적되지 않은 파일을 지웁니다 — git이 사본을 가진 적이 없어 되살릴 수 없고, -fdx는 .env처럼 무시 목록에 있던 파일까지 지우니 먼저 -n으로 확인합니다.git remote원격 저장소의 이름과 주소를 다룹니다 — 적어 두는 일뿐이라 add나 set-url을 해도 fetch·push를 하기 전에는 아무것도 오가지 않습니다.git fetch원격의 새 커밋을 받아 두기만 합니다 — 내 파일과 브랜치는 그대로라 merge나 rebase를 해야 반영되고, 서버에서 지운 브랜치는 --prune 전까지 남아 있습니다.git pullfetch와 merge를 한 번에 합니다 — 그래서 뜻하지 않은 merge 커밋이 생기고, --rebase나 --ff-only를 쓰면 막을 수 있습니다.git push내 커밋을 원격으로 올립니다 — --force는 원격 브랜치를 덮어써 남이 올린 커밋까지 지울 수 있으니, 원격이 움직였으면 거절하는 --force-with-lease를 씁니다.git tag커밋에 버전 같은 이름표를 붙입니다 — git push만으로는 태그가 올라가지 않아 태그 이름을 따로 밀어야 합니다.git rm파일을 색인과 디스크에서 함께 지웁니다 — --cached는 파일을 남기고 추적만 끊지만, 이미 커밋된 내용은 이력에 그대로 있어 유출된 비밀은 사라지지 않습니다.git mv파일을 옮기면서 그 사실을 바로 스테이지에 올립니다 — git은 이름 바꿈을 따로 저장하지 않고 내용이 닮은 것을 보고 추측하니, 대소문자만 바꾸는 이름은 macOS와 윈도에서 -f가 필요합니다.git ls-files디스크가 아니라 색인에 든 경로를 나열합니다 — 스크립트로 추적 파일을 훑을 때 믿을 수 있는 목록이고, -i는 혼자 쓰지 못해 -c나 -o와 --exclude-standard를 함께 적어야 합니다.git update-index색인을 직접 손봅니다 — 이 표시는 내 컴퓨터에만 남고 push되지 않으며, 추적 중인 설정 파일에 내 수정을 남겨 두는 것은 --assume-unchanged가 아니라 --skip-worktree입니다.git sparse-checkoutgit 2.25에 들어온 명령으로, 큰 저장소에서 지정한 폴더만 디스크에 둡니다 — 이력은 그대로 다 있고, cone 모드는 글롭이 아니라 폴더 이름을 받습니다.git reflogHEAD와 브랜치가 지나온 자리를 기록해 둡니다 — reset --hard나 브랜치 삭제로 잃은 커밋을 여기서 찾지만, 기록은 기본 90일이면 만료되고 내 컴퓨터에만 있습니다.git bisect커밋 구간을 반씩 갈라 문제가 처음 생긴 커밋을 찾습니다 — 끝나면 git bisect reset을 해야 하고, 잊으면 브랜치 없는 커밋 위에 그대로 남습니다.git describe가까운 태그를 기준으로 지금 커밋에 v1.2.0-5-gabc1234 같은 이름을 붙여 줍니다 — 기본은 주석 태그만 보므로 가벼운 태그에는 --tags가, 태그가 하나도 없으면 --always가 필요합니다.git rev-parseHEAD나 v1.2.0^ 같은 이름을 진짜 해시로 풀어 주고 저장소 위치도 알려 줍니다 — 스크립트에서 브랜치 이름은 --abbrev-ref HEAD로 얻고, 저장소 밖에서는 오류로 끝납니다.git fsck개체 저장소를 검사하고 아무도 가리키지 않는 커밋을 알려 줍니다 — reflog 기록까지 사라진 뒤 잃은 작업을 찾는 두 번째 방법이며, 알려 주기만 하고 고쳐 주지는 않습니다.git gc흩어진 개체를 묶고 아무도 안 쓰는 것을 버려 .git을 줄입니다 — --prune=now는 reflog가 붙들고 있던 커밋까지 버려서 reset을 되돌릴 안전망이 사라집니다.git archive커밋 한 시점의 파일들을 tar나 zip으로 내보냅니다 — .git과 추적되지 않은 파일이 들어가지 않아 폴더를 그대로 압축하는 것보다 깨끗한 배포 묶음이 됩니다.git applydiff 파일을 지금 작업 파일에 입힙니다 — 커밋을 만들지 않고 패치에 적힌 작성자도 읽지 않으니, 메일로 받은 패치는 am으로 붙이는 편이 맞습니다.git am메일로 온 패치를 원래 작성자와 메시지 그대로 커밋으로 만듭니다 — 중간에 실패하면 그 자리에 멈추므로 --continue·--skip·--abort로 마무리해야 합니다.git format-patch커밋마다 메일 꼴 .patch 파일 하나씩을 만듭니다 — format-patch main은 main 자신이 아니라 main 이후의 커밋을 뜻합니다.git shortlog커밋을 사람별로 묶어 세어 줍니다 — 같은 사람이 메일 주소를 두 개 썼으면 .mailmap으로 묶지 않는 한 두 사람으로 셉니다.git worktree같은 저장소에서 두 번째 작업 폴더를 꺼내 클론 없이 두 브랜치를 동시에 다룹니다 — 한 브랜치를 두 곳에 체크아웃할 수는 없고, 폴더를 손으로 지우면 prune까지 목록에 남습니다.git submodule다른 저장소를 커밋 하나에 고정해 내 저장소 안에 둡니다 — 그냥 클론하면 폴더가 비어 있어 update --init이 필요하고, 부모가 붙드는 것은 브랜치가 아니라 커밋입니다.

프로세스·시스템36

무엇이 돌고 있고 무엇이 자원을 먹는지 봅니다. 죽이기 전에 무엇인지 확인하는 것이 순서입니다.

ps지금 이 순간 돌고 있는 프로세스를 한 장으로 찍어 보여줍니다 — `ps aux`는 대시 없는 BSD 꼴이고 `ps -ef`는 POSIX 꼴이라, 두 꼴을 섞어 쓰는 것이 가장 흔한 실수입니다.top프로세스 목록을 몇 초마다 새로 그려 보여줍니다 — 옵션이 Linux와 macOS에서 아예 달라서, 한 번만 찍으려면 Linux는 `-b -n 1`, macOS는 `-l 1`입니다.htoptop을 색과 마우스로 다시 만든 것이라 F9로 바로 신호를 보낼 수 있지만, 기본으로 깔려 있지 않아 `apt install htop`이나 `brew install htop`이 먼저입니다.killPID에 신호를 보내 프로세스를 끝냅니다 — 기본 TERM은 정리할 틈을 주지만 `-9`는 막을 수 없어서, 열어둔 파일과 잠금 파일이 그대로 남습니다.killallPID이 아니라 이름으로 프로세스를 한꺼번에 끝냅니다 — 실행 파일 이름과 정확히 맞아야 해서 `killall chrome`은 "Google Chrome"을 놓칩니다.pkill이름 조각으로 맞는 프로세스를 모두 끝냅니다 — `-f` 없이는 명령 이름만 견주고 넓은 조각은 엉뚱한 것까지 죽이니, 같은 조각으로 pgrep을 먼저 돌려 봅니다.pgreppkill과 똑같은 규칙으로 맞는 프로세스의 PID만 찍어 줍니다 — 그래서 죽이기 전에 무엇이 걸리는지 확인하는 연습 삼기에 딱 맞습니다.jobs이 셸이 띄운 배경 작업만 번호를 붙여 보여주는 셸 내장 명령이라, 다른 터미널의 작업은 보이지 않고 번호는 PID가 아니라 `%1` 꼴로 씁니다.bgCtrl+Z로 멈춘 작업을 배경에서 다시 돌립니다 — 여전히 이 셸에 매달린 작업이라, 터미널을 닫으면 함께 죽습니다(살리려면 nohup이나 disown).fg배경이나 멈춘 상태의 작업을 다시 앞으로 끌어옵니다 — 이 셸의 작업에만 듣고, 가리킬 때는 PID가 아니라 `%1` 같은 작업 번호를 씁니다.nohupHUP 신호를 무시하게 만들어 로그아웃 뒤에도 명령이 살아 있게 합니다 — 배경으로 보내주지는 않으니 `&`는 직접 붙여야 하고, 출력은 조용히 ./nohup.out에 쌓입니다.niceCPU 우선순위를 낮춰 명령을 시작합니다 — 값은 19(가장 양보)에서 -20(가장 욕심)까지고 음수는 root만 되며, 디스크가 아니라 CPU에만 듣습니다(디스크는 ionice).renice이미 돌고 있는 프로세스의 우선순위를 바꿉니다 — 보통 사용자는 더 양보하게만 만들 수 있고, 한 번 낮춘 것을 되돌리려면 root가 필요합니다.systemctlsystemd 서비스를 켜고 끄고 상태를 봅니다 — `enable`은 부팅 때만 정하는 것이라 지금도 켜려면 `enable --now`이고, 유닛 파일을 고친 뒤에는 `daemon-reload`가 필요합니다.journalctlsystemd가 이진 형식으로 모아 둔 로그를 읽습니다 — /var/log/journal이 없으면 재부팅 때 로그가 사라지고, `-u`에는 유닛 이름을 정확히 적어야 합니다.serviceSysV 시절부터 남아 있는 얇은 겉껍데기라, systemd 기계에서는 그냥 systemctl로 넘겨주며 알아듣는 낱말이 더 적습니다.crontab사용자별 반복 일정표를 다룹니다 — cron은 PATH가 거의 비어 있고 로그인 설정을 읽지 않으니 경로를 전부 절대경로로 적어야 하고, `crontab -r`은 묻지 않고 표 전체를 지웁니다.at정해진 시각에 명령을 딱 한 번 돌립니다 — atd 데몬이 떠 있어야 하고(요즘 배포판은 깔려 있지도 않습니다), 출력은 화면이 아니라 메일로 갑니다.uptime기계가 켜져 있던 시간과 부하 평균을 한 줄로 보여줍니다 — 세 숫자는 1·5·15분 동안 실행을 기다린 프로세스의 평균이고 백분율이 아니라서, 4코어에서 4.00이면 꽉 찬 것입니다.freeLinux에서 메모리와 스왑이 얼마나 남았는지 셉니다 — 봐야 하는 칸은 free가 아니라 available입니다(캐시는 필요하면 내주니까), macOS에는 없고 vm_stat을 씁니다.vmstat메모리·스왑·디스크·CPU 통계를 정해진 간격으로 계속 찍습니다 — 첫 줄은 지금이 아니라 부팅 이후의 평균이라 반드시 버리고, si/so와 wa 칸부터 봅니다.iostat디스크마다 얼마나 읽고 쓰고 얼마나 기다리는지 보여줍니다 — 첫 묶음은 부팅 이후 평균이고, Linux에서는 sysstat을 깔아야 하며 macOS는 `-w 1 -c 5`처럼 옵션이 다릅니다.lsblk디스크와 그 안의 파티션을 나무 모양으로 늘어놓습니다 — 파티션이 잡히지 않은 빈 공간은 보여주지 않고(그건 fdisk나 parted), Linux 전용이라 macOS에서는 `diskutil list`를 씁니다.uname커널 이름과 판, 그리고 아키텍처를 알려줍니다 — 배포판 이름은 알려주지 않으니 그건 /etc/os-release(macOS는 `sw_vers`)를 읽어야 하고, `-o`는 GNU에만 있습니다.hostname이 기계의 이름을 찍거나 바꿉니다 — `hostname web01`은 재부팅까지만 버티니 오래 두려면 Linux는 `hostnamectl`, macOS는 `scutil --set HostName`이고, IP를 다 보는 `-I`는 Linux에만 있습니다.date지금 시각을 원하는 꼴로 찍거나 날짜를 계산합니다 — `+`로 시작하는 형식은 어디서나 같지만, 날짜를 옮기는 옵션은 GNU가 `-d`, macOS/BSD가 `-v`와 `-j -f`로 완전히 다릅니다.env환경 변수를 다 찍거나, 변수를 얹어 명령 하나를 돌립니다 — 그 변수는 그 한 번의 실행에만 붙고 셸에는 아무것도 남지 않습니다.export변수를 자식 프로세스에게 물려주도록 표시합니다 — 이 셸을 닫으면 사라지니 오래 두려면 ~/.bashrc나 ~/.zshrc에 적어야 하고, export 없이 `VAR=x`만 하면 자식 프로그램은 그 변수를 못 봅니다.whichPATH를 뒤져 그 이름의 실행 파일이 어디 있는지 알려줍니다 — PATH만 보기 때문에 별칭·함수·셸 내장 명령에 대해서는 거짓을 말하고, 정직한 답은 `type -a`나 `command -v`가 줍니다.type어떤 이름이 실제로 무엇인지 — 별칭인지 함수인지 내장 명령인지 파일인지 — 셸에게 직접 물어봅니다. 그래서 PATH만 보는 which가 놓치는 것을 봅니다.lsof열려 있는 파일과 소켓을 모두 늘어놓아 "3000번 포트를 누가 쥐고 있나"에 답합니다 — sudo 없이는 내 프로세스만 보이니, 빈 결과가 포트가 비었다는 뜻은 아닙니다.fuser어떤 파일·마운트·포트를 쓰고 있는 프로세스를 찾아내고 원하면 죽입니다 — `-k`는 SIGKILL을 보내 정리할 틈을 주지 않으며, Linux(psmisc)에만 있고 macOS판에는 `-cfu`뿐입니다.watch같은 명령을 몇 초마다 다시 돌리며 화면을 갈아 그립니다 — 파이프나 `*`가 든 명령은 반드시 따옴표로 묶어야 하고(안 그러면 셸이 watch 자신에게 한 번만 적용합니다), macOS에는 기본으로 없습니다.timeout명령에 시간 제한을 걸고 넘기면 끊습니다 — 제한이 걸리면 종료 코드 124가 나오고, 기본 신호는 TERM이라 멈춘 프로그램은 무시할 수 있으니 `-k`로 KILL을 뒤따르게 합니다(GNU coreutils, macOS에는 없습니다).strace프로세스가 커널에 던지는 시스템 호출을 하나씩 찍어 어디서 멈췄는지 보여줍니다 — 출력이 stderr로 나가므로 `2>&1`로 돌려야 하고, ptrace 권한(보통 sudo)이 필요하며 Linux 전용입니다(macOS는 dtruss).dmesg커널이 남긴 메시지 고리버퍼를 읽어 디스크나 USB가 방금 무슨 일을 겪었는지 보여줍니다 — 크기가 정해진 버퍼라 오래된 줄은 이미 밀려났고, 요즘 배포판은 대개 root를 요구합니다(macOS는 `log show`).

네트워크28

연결이 안 될 때 어디까지 갔는지 좁혀 갑니다 — 이름이 안 풀리는지, 길이 없는지, 포트가 막혔는지.

curl주소 하나를 그대로 받아 본문을 화면에 뿌립니다 — 브라우저와 달리 `-L` 없이는 넘김을 따라가지 않아서, 301이 오면 빈 응답처럼 보입니다.wget주소를 파일로 내려받고 넘김도 알아서 따라갑니다 — curl은 시키지 않으면 화면에 뿌리는 것이 차이이고, macOS에는 기본으로 깔려 있지 않습니다.pingICMP echo를 보내 상대가 답하는지, 얼마나 걸리는지 봅니다 — 답이 없다고 죽은 것은 아닙니다. 방화벽이 ICMP만 버리고 TCP는 잘 받는 경우가 흔합니다.traceroute목적지까지 지나는 라우터를 한 줄씩 늘어놓습니다 — 중간에 `* * *`가 보이면 길이 끊긴 것이 아니라 그 라우터가 답하지 않기로 한 것입니다.digDNS 서버에 직접 물어 기록을 그대로 보여줍니다 — /etc/hosts와 시스템 캐시를 건너뛰기 때문에 브라우저가 보는 것과 다를 수 있고, 배포판에 따라 dnsutils나 bind-utils를 깔아야 있습니다.nslookup이름을 주소로 바꿔 보는 옛 도구로 아직 돌기는 하지만, 출력 꼴과 종료 상태가 일정하지 않아 스크립트에는 맞지 않고 지금은 dig가 그 자리를 대신합니다.host이름을 물으면 주소와 메일 서버를 두어 줄로 짧게 답하는 도구입니다 — 빠른 확인에는 가장 편하지만 기록 전체를 보려면 dig를 써야 합니다.ssLinux에서 열린 소켓을 늘어놓는 요즘 도구로, netstat 자리를 이어받았고 연결이 많은 기계에서 훨씬 빠릅니다 — 다만 `-p`로 프로세스 이름을 보려면 root여야 합니다.netstat소켓과 경로표를 보여주는 옛 도구입니다 — Linux에서는 ss에 자리를 넘겼고 아예 안 깔려 있기도 하며, macOS에는 남아 있지만 소켓의 주인 프로세스를 알려주지 못해 그 답은 lsof가 줍니다.ipLinux에서 주소·경로·이웃표를 모두 다루는 하나의 명령으로 ifconfig와 route와 arp를 대신합니다 — 여기서 바꾼 것은 재부팅하면 사라지니, 남기려면 네트워크 설정 파일에 적어야 합니다.ifconfig네트워크 인터페이스를 보고 손대는 옛 명령입니다 — Linux에서는 `ip addr`가 대신하고 아예 안 깔려 있기도 하며 ip로 더한 주소를 다 못 보여주지만, macOS에서는 여전히 이것이 진짜 도구입니다.route커널 경로표를 보고 고치는 명령이지만 Linux에서는 `ip route`로 넘어갔고, BSD/macOS에서는 `route -n get default`처럼 문법이 아예 달라서 두 쪽 예시를 섞으면 통하지 않습니다.arp같은 랜에 있는 이웃의 MAC 주소를 모아둔 표를 보여줍니다 — 라우터를 넘어간 상대는 절대 여기 없고, Linux에서는 `ip neigh`가 요즘 도구입니다.nc (netcat)TCP·UDP를 맨손으로 붙여 포트가 답하는지 보고 두 기계 사이에 관을 놓습니다 — 이름이 같고 서로 안 맞는 판이 셋(OpenBSD·GNU·Nmap ncat) 있어서 `-z`나 `-p`가 없을 수도 있습니다.telnet평문 TCP 연결을 열어 주고받은 것이 그대로 회선에 흐르니 로그인에는 절대 쓰지 않고(그건 ssh), 지금 남은 쓸모는 포트가 답하는지 보는 것뿐이며 나올 때는 Ctrl+] 다음에 quit입니다.ssh다른 기계에 암호화된 셸을 엽니다 — 비밀 키 파일이 남에게도 읽히면 ssh는 아예 거부하니 `chmod 600`이 필요하고, 포트는 여기서 `-p`인데 scp와 sftp에서는 `-P`입니다.ssh-keygen공개 키와 비밀 키 한 쌍을 만듭니다 — 서버에 올리는 것은 `.pub` 쪽뿐이고, 암구호 없이 만든 키는 그 파일 하나만 있으면 누구든 그대로 로그인할 수 있는 상태입니다.ssh-copy-id내 공개 키를 서버의 ~/.ssh/authorized_keys에 붙여 넣어 비밀번호를 그만 묻게 만듭니다 — 처음 한 번은 비밀번호 로그인이 열려 있어야 하고, `-i`에는 비밀 키가 아니라 `.pub` 파일을 줍니다.sftpssh 연결 위에서 파일을 주고받는 대화식 도구입니다 — 포트가 ssh의 `-p`가 아니라 대문자 `-P`이고, 원격 셸 명령은 못 돌리며 put·get·ls 같은 자기 명령만 압니다.scpssh를 타고 파일을 한 번에 복사합니다 — 포트는 대문자 `-P`이고 원격 쪽 경로에는 콜론이 필요하며, 크거나 되풀이하는 전송이면 안 바뀐 것을 건너뛰고 이어받는 rsync가 낫습니다.iptables지금 돌고 있는 패킷 필터를 고칩니다 — 규칙은 위에서 아래로 먼저 맞는 것이 이기므로 ACCEPT 뒤에 붙인 DROP은 영원히 안 걸리고, 저장하지 않으면 재부팅에 사라지며, 22번을 열기 전에 기본 정책을 DROP으로 두면 원격 기계에서 스스로 잠깁니다.ufwDebian·Ubuntu에서 iptables를 쉬운 낱말로 감싼 방화벽입니다 — `enable` 전에 SSH를 먼저 열어야 지금 붙어 있는 연결이 끊기지 않고, Docker는 포트를 iptables에 직접 꽂기 때문에 ufw 규칙이 그 포트를 막지 못합니다.tcpdump회선을 지나는 패킷을 그대로 잡아 보여줍니다 — root가 필요하고, 무엇을 잡을지는 옵션이 아니라 뒤에 붙이는 자기만의 필터 문법(`port 443 and host x`)이며, 바쁜 인터페이스에서 필터 없이 잡으면 화면이 순식간에 파묻힙니다.whois도메인이나 IP 대역의 등록 정보를 조회합니다 — 개인 정보는 대개 가려져 있고 TLD마다 서버가 제 나름의 꼴로 답하기 때문에, 스크립트에서 그 출력을 파싱하는 것은 쉽게 깨집니다.nmap상대 기계에서 어떤 포트가 답하는지 훑습니다 — `-sS`와 `-O`는 root가 필요하고, 내 것이 아닌 기계를 훑으면 상대 로그에 공격으로 남고 나라에 따라 불법이니 자기 망에서만 씁니다.openssl s_clientTLS 연결을 맨손으로 열어 인증서와 악수 과정을 들여다봅니다 — `-servername`을 빼면 한 IP에 여러 사이트가 있는 서버가 기본 인증서를 내주어 "엉뚱한" 것이 보이고, `< /dev/null`을 붙이지 않으면 입력을 기다리며 멈춰 있습니다.speedtest가까운 서버와 실제로 주고받아 회선 속도를 잽니다 — 어느 운영체제에도 기본으로 없고, 이름이 같은 프로그램이 둘(Ookla의 speedtest와 파이썬 speedtest-cli) 있어 옵션이 서로 다릅니다.mtrtraceroute와 ping을 한 표에 합쳐 계속 갱신하니, 간간이 끊기는 손실을 잡는 데 맞습니다 — 중간 홉의 손실은 대개 그 라우터가 ICMP 응답을 아껴 그런 것이고, 마지막 홉까지 이어지는 손실만 실제 문제입니다.

압축·전송14

압축과 묶음은 다른 일입니다. tar가 묶고 gzip이 줄이며, .tar.gz는 그 둘을 겹친 것입니다.

tar파일을 한 묶음으로 묶기만 하고 그 자체로는 압축하지 않습니다 — 줄이는 일은 `-z`(gzip)·`-j`(bzip2)·`-J`(xz)가 맡고, `-c` 만들기·`-x` 풀기·`-t` 들여다보기 가운데 하나만 골라 앞에 두며, 옛 꼴에서는 `-f`가 옵션 가운데 마지막이라 그 바로 뒤에 묶음 이름이 옵니다.gzip파일 하나를 .gz로 압축합니다 — 기본 동작이 원본을 지우고 .gz만 남기는 것이라, 원본을 두려면 `-k`를 붙이거나 `-c`로 표준출력에 받아야 하고, 여러 파일을 하나로 묶지는 못해 tar와 함께 씁니다.gunzip.gz를 풀어 원래 파일로 되돌립니다 — 성공하면 .gz 쪽을 지우니 남기려면 `-k`이고, 같은 이름의 파일이 이미 있으면 `-f` 없이는 거부하며, 디스크에 쓰지 않고 바로 흘려보내려면 `-c`(zcat과 같습니다)를 씁니다.zip압축까지 스스로 하는 묶음 꼴이라, Windows에서 아무것도 깔지 않고 그냥 열리는 것이 이것입니다 — 폴더를 담으려면 `-r`이 있어야 하고(없으면 폴더 항목만 들어가고 속은 비어 있습니다), `-e`로 거는 잠금은 옛 ZipCrypto라 약합니다.unzip.zip을 풀어 놓습니다 — `-d`를 안 주면 지금 폴더에 그대로 쏟아지니 `-l`로 안에 상위 폴더가 있는지 먼저 보고, 옛 Windows에서 만든 것은 이름이 깨져 `-O CP932`가 필요하며, `-P`로 적은 비밀번호는 셸 기록과 ps에 그대로 남습니다.bzip2gzip보다 느리지만 더 작게 줄입니다 — gzip과 마찬가지로 원본을 지우고 .bz2만 남기니 남기려면 `-k`가 필요하고, tar와 함께 쓸 때 붙일 글자는 `-j`이며 푸는 것은 `-d`(=bunzip2)입니다.xz흔히 쓰는 셋 가운데 가장 작게 줄이지만 느리고 `-9`에서는 700 MB 남짓 메모리를 씁니다 — 기본이 한 코어라 `-T0`을 붙여야 여럿을 쓰고, 원본은 `-k` 없이는 사라지며 tar에 붙일 글자는 대문자 `-J`입니다.zcat.gz 안의 내용을 디스크에 풀지 않고 표준출력으로 바로 흘려보냅니다 — 그래서 돌려 놓은 로그를 그 자리에서 grep할 수 있고, 압축이 아닌 파일까지 섞어 읽으려면 `-f`이며, bzip2·xz·zstd에는 bzcat·xzcat·zstdcat이 따로 있습니다.7za·x·e·l 같은 낱말을 맨 앞에 두고 쓰는 도구로, .7z뿐 아니라 zip·tar·rar까지 읽고 압축률도 높은 편입니다 — 내보낼 폴더는 `-o` 뒤에 띄어쓰기 없이 붙여 적어야 하고, 이름까지 감추려면 `-p`에 `-mhe=on`을 더합니다.dd블록 단위로 그대로 복사해 디스크 이미지를 쓰거나 굽습니다 — `of=`에 적은 대상은 확인 한 번 없이 0번 블록부터 덮어써지고 되돌릴 방법이 없으니, Enter를 누르기 직전에 lsblk로 장치 이름을 다시 확인하고, 속도는 `bs=4M`, 진행은 `status=progress`(macOS는 Ctrl+T)로 봅니다.split큰 파일을 여러 조각으로 자릅니다 — 기본이 1000줄씩 자르는 것이라 크기로 자르려면 `-b 100M`처럼 적어야 하고, 접두사를 안 주면 조각 이름이 xaa·xab가 되며, 되붙이는 것은 `cat part_* > file` 하나로 끝나지만 그것은 접미사가 순서대로 정렬되기 때문입니다.cpio무엇을 담을지 표준입력으로 받은 이름 목록에서 정하는 옛 묶음 도구라, 그 목록은 대개 find가 만듭니다 — `-o`가 묶기, `-i`가 풀기, `-t`가 목록이고, initramfs가 쓰는 꼴은 `-H newc`이며, 남이 준 묶음은 절대경로로 튀어나오지 않게 `--no-absolute-filenames`를 붙입니다.zstdgzip과 같은 크기를 몇 배 빠르게 내고 `-19`에서는 xz에 가까운 크기까지 훨씬 짧은 시간에 만드는 요즘 압축기입니다 — gzip과 달리 원본을 그대로 두고(지우려면 `--rm`), `-T0`으로 모든 코어를 쓰며 tar에서는 `--zstd`로 부릅니다.rar독점 형식이라 만드는 rar는 유료이고 푸는 unrar만 공짜로 옵니다 — 남이 보낸 .rar는 `unrar x`(적힌 경로 그대로)나 RARLAB에서 아무것도 안 깔고 `7z x`로 열면 되며, `e`는 경로를 눌러 펴고 `-hp`는 이름까지 감추며 `-v100m`은 여러 권으로 나눕니다.

권한·소유15

숫자 모드와 문자 모드가 같은 것을 가리킵니다. 755와 u=rwx,go=rx는 같은 뜻입니다.

chmod파일과 디렉터리의 권한 비트를 정합니다. chmod -R 755는 평범한 파일까지 실행 가능으로 만들므로, 파일은 그대로 두려면 대문자 X를 씁니다.chown파일의 주인과 그룹을 바꿉니다. 남에게 파일을 넘기는 것은 root만 할 수 있어 거의 늘 sudo가 붙습니다.chgrp파일의 그룹만 바꿉니다. chown이 :group으로 같은 일을 하고, root가 아니라면 자기가 속한 그룹으로만 바꿀 수 있습니다.umask새로 만드는 파일에서 어떤 권한 비트를 뺄지 정합니다. 더하는 값이 아니라 빼는 가리개라서 022가 파일 644, 디렉터리 755가 되고, 이미 있는 파일은 건드리지 않습니다.sudo명령 하나를 다른 사용자, 보통 root로 실행합니다. sudo cmd > file의 > 는 내 셸에서 열리므로 root 소유 파일에는 실패하고, 그때는 tee를 씁니다.su그 사용자의 비밀번호로 다른 사용자가 됩니다 — 내 비밀번호를 묻는 sudo와 반대이고, 대시를 빼면 내 PATH가 남아 command not found가 납니다.id프로세스가 어떤 사용자와 그룹으로 돌아가는지 찍습니다. id -u가 0이면 root라는 뜻이라, 스크립트가 관리자 권한을 확인하는 표준 방법입니다.groups사용자가 어떤 그룹에 드는지 늘어놓습니다. usermod로 방금 넣은 그룹은 다시 로그인하기 전까지 나오지 않는데, 목록이 세션이 열릴 때 굳기 때문입니다.whoami지금 유효한 사용자 이름을 찍습니다. 로그인한 이름이 아니라서 sudo나 su 안에서는 root로 나옵니다.passwd로그인 비밀번호를 바꾸고 그 해시를 /etc/shadow에 넣습니다. macOS에는 리눅스 쪽 옵션이 거의 없어 dscl이나 설정 화면을 씁니다.getfacl소유자, 그룹, 기타 말고 따로 붙은 접근 권한 목록을 찍습니다. acl 꾸러미를 넣은 리눅스의 것이고, macOS는 ls -le로 자기 방식의 ACL을 보여 줍니다.setfacl주인을 바꾸지 않고 특정 사용자나 그룹에게만 권한을 더 줍니다. ACL이 생기면 ls의 권한 뒤에 +가 붙고, mask 항목이 준 권한을 조용히 깎을 수 있습니다.chattr파일시스템 수준의 속성을 붙입니다. +i를 걸면 root도 먼저 풀지 않고는 고칠 수 없고, 리눅스의 ext4, xfs, btrfs에서만 되며 macOS에는 없습니다.xattrmacOS에서 확장 속성을 읽고 지웁니다. 대개는 com.apple.quarantine — 앱이 손상되었다는 그 경고의 정체이고, 리눅스는 getfattr와 setfattr을 씁니다.visudo/etc/sudoers를 잠금과 문법 검사를 거쳐 고칩니다. 그 파일을 직접 고쳐 틀리면 모두가 sudo를 못 쓰게 되는데, 그것을 막는 것이 이 명령입니다.

패키지·런타임25

무엇을 어디에 넣는지가 문제입니다. 프로젝트 안인지 시스템 전체인지 먼저 정하세요.

npm installpackage.json에 적힌 의존성을 받아 node_modules에 넣고 package-lock.json을 갱신합니다 — npm 7부터 peer 의존성도 함께 설치되고, --production은 --omit=dev로 바뀌었습니다.npm cinode_modules를 지우고 package-lock.json에 적힌 그대로만 설치합니다 — 잠금 파일을 고치지 않고 package.json과 어긋나면 바로 실패해서, CI에서는 install 대신 이것을 씁니다.npm runpackage.json의 scripts에 적어 둔 명령을 실행합니다 — 스크립트에 옵션을 넘기려면 --를 먼저 적어야 하고, run 없이 부를 수 있는 것은 start와 test뿐입니다.npm initpackage.json을 만들어 줍니다 — npm init <이름> 꼴은 전혀 다른 일로, create-<이름> 패키지를 받아 실행합니다.npx패키지의 실행 파일을 불러 씁니다 — node_modules/.bin을 먼저 보고 없으면 원격에서 임시로 받아 오니, 오타로 엉뚱한 패키지가 실행되지 않게 하려면 --no를 붙입니다.yarn add패키지를 넣고 yarn.lock을 갱신합니다 — yarn만 치면 install이 되고, Yarn 2부터는 yarn global add가 없어져 한 번 쓰는 도구는 yarn dlx로 실행합니다.pnpm add패키지를 공용 저장소에 두고 node_modules에서 링크로 잇습니다 — 워크스페이스 루트에서는 그냥 add를 거부하니 -w나 --filter로 어디에 넣을지 밝혀야 합니다.npm audit설치된 의존성에 알려진 취약점이 있는지 알려 줍니다 — fix --force는 호환이 깨지는 상위 버전까지 올리고, 개발용 깊은 의존성 경고는 손쓸 수 없는 경우가 많습니다.npm publish패키지를 레지스트리에 올립니다 — @scope 이름은 기본이 비공개라 --access public이 필요하고, 한 번 올린 버전 번호는 다시 쓸 수 없으니 --dry-run으로 담길 파일부터 확인합니다.node --versionPATH에서 먼저 잡히는 node의 버전을 찍어 줍니다 — 버전 관리자가 셸마다 다른 것을 가리키기 때문에 편집기 터미널이나 CI가 다른 버전을 쓰는 일이 흔합니다.nvm use지금 셸이 쓸 node 버전을 바꿉니다 — 그 셸에만 걸리기 때문에 새 터미널이나 CI는 기본값으로 돌아가고, nvm은 셸 함수여서 스크립트나 Makefile에서는 nvm.sh를 먼저 읽어야 합니다.brew installmacOS와 Linux에서 미리 빌드된 bottle을 받아 설치합니다 — 화면이 있는 앱은 --cask로 넣고, 새 버전으로 올리는 일은 install이 아니라 brew update와 brew upgrade가 맡습니다.apt-get install이미 받아 둔 패키지 목록에서 골라 설치합니다 — 목록이 오래되면 "Unable to locate package"가 나오니 apt-get update가 먼저이고, 스크립트에서는 사람 눈에 맞춘 apt보다 apt-get이 안전합니다.apt update패키지 목록만 새로 받아 옵니다 — 이것만으로는 아무것도 설치되거나 올라가지 않아 apt upgrade가 뒤따라야 하고, 갓 만든 컨테이너는 목록이 비어 있어 이 명령이 첫걸음입니다.dnf install활성 저장소에서 의존성까지 풀어 설치합니다 — 메타데이터를 스스로 만료시켜 apt처럼 update를 따로 치지 않아도 되고, RHEL 8 이후 yum은 dnf로 가는 링크이며 Fedora 41부터는 dnf5입니다.pacman -SArch의 sync 저장소에서 패키지를 설치합니다 — 롤링 배포라서 -Sy로 목록만 새로 받고 설치하면 라이브러리가 어긋나는 부분 업그레이드가 되니 항상 -Syu로 함께 올립니다.pip install지금 활성인 파이썬에 패키지를 넣습니다 — pip이 다른 인터프리터의 것일 수 있어 python -m pip으로 부르는 편이 안전하고, PEP 668 이후 시스템 파이썬은 가상환경 밖 설치를 거부합니다.pip freeze설치된 패키지와 버전을 한 줄씩 찍어 requirements.txt로 만듭니다 — 직접 고른 것뿐 아니라 딸려 온 의존성까지 다 나오므로 반드시 그 가상환경 안에서 실행해야 합니다.python -m venv폴더 하나에 독립된 파이썬과 site-packages를 만듭니다 — 만들기만 해서는 아무 일도 없어 activate하거나 .venv/bin/python을 직접 불러야 하며, 경로가 안에 박혀 있어 폴더 이름을 나중에 바꾸면 깨집니다.docker run이미지에서 컨테이너를 새로 만들어 띄웁니다 — 두 번 치면 컨테이너가 둘이 되니 멈춘 것을 다시 켜는 일은 docker start이고, -p 없이는 host에서 닿지 않으며 -v 없이 쓴 것은 컨테이너와 함께 사라집니다.docker ps지금 돌고 있는 컨테이너만 보여줍니다 — 시작하자마자 죽은 컨테이너는 -a를 붙여야 보이니, run이 아무 일도 안 한 것처럼 보이면 여기를 봅니다.docker buildDockerfile로 이미지를 만듭니다 — 끝의 점은 데몬에게 보낼 빌드 컨텍스트라서 폴더가 크면 빌드가 느려지고(.dockerignore로 줄입니다), COPY는 그 컨텍스트 안의 파일만 볼 수 있습니다.docker compose upcompose.yaml에 적힌 서비스를 한 묶음으로 띄웁니다 — 하이픈이 붙은 docker-compose는 은퇴한 v1이고 지금은 docker compose 플러그인이며, 이미 있는 컨테이너는 --build나 --force-recreate 없이는 그대로 다시 쓰입니다.docker exec이미 돌고 있는 컨테이너 안에서 다른 프로세스를 실행합니다 — 멈춘 컨테이너에는 쓸 수 없고, 가벼운 이미지에는 bash가 없어 sh로 들어가야 합니다.docker logs컨테이너의 주 프로세스가 stdout·stderr로 쓴 것을 보여줍니다 — 앱이 컨테이너 안 파일에 로그를 쓰면 여기에는 아무것도 안 나오고, 컨테이너를 지우면 로그도 함께 사라집니다.

읽는 방법

  • 대괄호 [ ]는 넣어도 되고 안 넣어도 되는 자리입니다.
  • 점 셋 …은 여러 개를 이어 쓸 수 있다는 뜻입니다.
  • 옵션은 대소문자를 가립니다 — -r과 -R이 다른 명령도 있습니다.

자주 묻는 것

Q. 명령 이름은 왜 번역하지 않나요?

그대로 쳐야 동작하기 때문입니다. ls를 옮기면 옮긴 말은 셸이 모르는 이름이 됩니다. 옵션도 같은 이유로 그대로 둡니다 — 설명만 언어를 따릅니다.

Q. 맥과 리눅스에서 옵션이 다르던데요.

다릅니다. macOS는 BSD 계열이라 GNU 옵션이 없는 경우가 있습니다 — sed -i가 인자를 요구하거나 ps가 -ef를 안 받는 식입니다. 갈리는 자리는 설명에 어느 쪽인지 적어 두었습니다.

Q. 되돌릴 수 없는 명령은 어떻게 알아보나요?

설명에 그 사실을 적었습니다. rm은 휴지통을 거치지 않고, dd는 of=를 잘못 쓰면 디스크를 덮어쓰며, git reset --hard와 git clean -fd는 저장 안 한 작업을 버립니다.