- -P
- 심볼릭 링크를 해석한 물리적 경로 출력
- -L
- 심볼릭 링크를 유지한 논리적 경로 출력(기본값)
pwd지금 어디에 있지?
pwd -P심볼릭 링크를 거쳐 들어왔을 때 실제 경로
파일과 권한부터 네트워크, systemd, 텍스트 처리까지 작업별로 정리한 Linux 명령어. 모든 항목에 옵션, 복사 가능한 예시, macOS 참고 사항이 있습니다.
마지막 확인: 2026-10-18, GNU coreutils 9.x, util-linux, procps-ng, iproute2, systemd, bash 5.2 매뉴얼. macOS 관련 내용은 macOS 26 man 페이지 기준 기준.
파일을 읽고, 로그를 넘겨 보고, 터미널에서 편집하고, 버전을 비교합니다.
cat /etc/os-release파일 출력
cat part1.txt part2.txt > whole.txt이어 붙이기
cat -A script.sh | head숨은 탭과 Windows ^M 줄 끝 찾기
macOS/BSD: macOS cat에는 -A가 없습니다. 같은 결과를 보려면 cat -vet를 쓰세요.
tac access.log | head최신 로그 줄부터
macOS/BSD: macOS에는 없습니다. tail -r file을 쓰세요.
less /var/log/syslog로그 읽기
journalctl -u nginx | less -S긴 줄을 줄바꿈 없이
head -n 20 data.csv헤더와 처음 몇 행
head -c 512 file.bin | xxd바이너리의 앞부분 들여다보기
macOS/BSD: macOS head는 음수 개수를 받지 않습니다.
tail -n 50 app.log마지막 50줄
tail -F /var/log/nginx/access.log로테이션되는 로그 지켜보기
tail -n +2 data.csvCSV 헤더 줄 건너뛰기
sudo nano /etc/hosts시스템 파일 편집
화면 아래쪽 단축키 표시줄에 키가 나옵니다. ^는 Ctrl, M-는 Alt를 뜻합니다.
vim +42 app.py42번째 줄에서 열기
diff -u old.conf new.conf읽기 쉬운 변경 내용 보기
diff -rq dir1/ dir2/두 트리 사이에서 다른 파일
diff <(sort a.txt) <(sort b.txt)프로세스 치환으로 정렬한 뒤 비교
make 2>&1 | tee build.log빌드를 지켜보면서 로그도 남기기
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.confroot 소유 파일에 덧붙이기(리디렉션은 셸이 하므로 sudo echo >>는 실패함)
printf '%s\n' "$var"-n으로 시작하는 값이라도 변수를 안전하게 출력
printf '%-12s %6.2f\n' disk 93.5정렬된 열
echo -e와 echo -n은 셸마다 다르게 동작하지만, printf는 어디서나 똑같이 동작합니다.
column -t -s, data.csv | less -S간단한 CSV를 표로 읽기
mount | column -t공백으로 구분된 출력을 열 맞추기
xxd image.png | head16진수와 ASCII를 나란히
hexdump -C file.bin | head표준 16진수 덤프
xxd는 vim 패키지에 들어 있고, hexdump는 util-linux에 있습니다(최신 Debian/Ubuntu에서는 bsdextrautils).
strings -n 8 firmware.bin | less버전 문자열, URL, 경로 찾기
Linux에서는 binutils에 포함되어 있습니다.
파일을 누가 읽고, 쓰고, 실행할 수 있는지 확인하고 바꿉니다.
ls -l deploy.sh-rwxr-x--- 1 alice devs 812 Oct 18 09:12 deploy.sh
첫 글자는 유형입니다(- 파일, d 디렉터리, l 심볼릭 링크). 이어서 소유자, 그룹, 그 밖의 모든 사용자 순으로 세 글자씩 묶입니다. r=4, w=2, x=1이므로 rwxr-x---는 750입니다.
chmod 644 index.html소유자 읽기/쓰기, 모두 읽기: 일반 파일
chmod 755 deploy.sh소유자 전부, 나머지 읽기/실행: 스크립트와 디렉터리
chmod 600 ~/.ssh/id_ed25519나만 읽을 수 있는 개인 키. 권한이 더 느슨하면 ssh가 거부함
chmod +x script.sh스크립트를 실행 가능하게
chmod go-w file그룹과 나머지의 쓰기 권한 제거
chmod -R u=rwX,go=rX site/대문자 X는 디렉터리와 이미 실행 권한이 있던 파일에만 실행 권한을 줍니다
find site/ -type d -exec chmod 755 {} +올바른 해결책 1: 디렉터리는 755
find site/ -type f -exec chmod 644 {} +2: 파일은 644
위험: 컴퓨터의 모든 사용자와 침해된 모든 서비스에 트리 전체의 쓰기 권한을 주고, 모든 파일을 실행 가능으로 표시하며, ~/.ssh가 777이면 OpenSSH가 키를 거부합니다. /etc나 /usr에 적용하면 sudo와 시스템이 망가질 수 있습니다. 대신 chown으로 소유권을 고치거나 두 find 명령어를 쓰세요.
sudo chown -R www-data:www-data /var/www/site웹 루트를 웹 서버 사용자에게 넘기기
sudo chown "$USER": file.txtroot가 만든 파일의 소유권 가져오기
위험: /, /usr, /etc에 sudo chown -R을 실행하면 sudo, passwd, 서비스가 의존하는 setuid 비트와 소유권이 지워져, 복구하려면 보통 재설치해야 합니다. 경로를 다시 확인하세요.
chgrp -R developers /srv/shared공유 폴더를 팀 그룹에 넘기기
umask현재 마스크 표시, 보통 0022
umask 077이 셸에서 새 파일은 600, 디렉터리는 700
마스크는 비트를 뺍니다. 파일은 666, 디렉터리는 777에서 시작하므로 022이면 644와 755가 됩니다.
sudo systemctl restart nginx관리자 명령어 하나
sudo !!직전 명령어를 sudo로 다시 실행
sudo -u postgres psql서비스 사용자로 실행
su - deploydeploy 사용자의 환경으로 로그인
sudo su -root에 비밀번호가 없을 때 root 셸(sudo -i와 같음)
setfacl -m u:alice:rw report.xlsx그룹은 바꾸지 않고 alice가 읽고 쓸 수 있게
getfacl report.xlsx모든 항목 보기
setfacl -R -m g:devs:rwX /srv/app그룹에 트리 전체 접근 권한 주기
ls -l 권한 문자열 끝에 +가 있으면 파일에 ACL이 있다는 뜻입니다.
sudo chattr +i /etc/resolv.conf-i를 풀기 전까지 root를 포함해 아무도 수정하거나 삭제할 수 없음
lsattr /etc/resolv.conf속성 보기. i는 변경 불가
ext4, XFS, Btrfs에서 지원됩니다. root로도 "Operation not permitted"가 나오면 lsattr를 확인하세요.
실행 중인 것을 찾고, 멈추고, 백그라운드에서 실행합니다.
ps aux | grep [n]ginx[n] 트릭으로 grep 자신을 결과에서 뺌
ps aux --sort=-%mem | head메모리를 가장 많이 쓰는 프로세스
ps -o pid,ppid,etime,cmd -p 1234프로세스가 얼마나 오래 실행 중인지
macOS/BSD: macOS ps에는 --sort가 없습니다. ps aux -m(메모리순)이나 ps aux -r(CPU순)을 쓰세요.
pstree -pPID 포함
pstree -p 1234프로세스가 띄운 하위 프로세스
top -b -n 1 | head -20티켓에 붙여 넣을 수 있는 스냅숏
macOS/BSD: macOS top은 다른 프로그램입니다. top -o cpu나 top -o mem으로 정렬하세요.
htop -u www-data한 사용자의 프로세스만
apt install htop / dnf install htop으로 설치하세요.
pgrep -a nginxPID와 명령줄
pgrep -f 'python manage.py runserver'인수로 스크립트 찾기
macOS/BSD: macOS에서 -a는 "상위 프로세스 포함"이라는 뜻입니다. 이름과 인수를 보려면 pgrep -lf를 쓰세요.
pkill -f "node server.js"Node 앱 하나 중지
pkill -HUP nginx다시 불러오기 시그널 보내기
pgrep -af node종료 전에 -f가 무엇과 일치할지 미리 보기
패턴은 이름 어디와도 일치하는 정규식입니다. pkill node는 nodejs-helper도 건드립니다. 먼저 pgrep으로 미리 확인하세요.
kill 1234정중하게 중지
kill -9 1234TERM이 무시될 때 최후의 수단
kill %1이 셸의 1번 작업 종료
먼저 그냥 kill을 쓰고 몇 초 기다리세요. -9는 정리 작업을 건너뛰므로 임시 파일, 잠금, 반쯤 쓴 데이터가 남을 수 있습니다.
killall firefox모든 Firefox 프로세스
Linux에서는 psmisc 패키지에 들어 있습니다.
jobs이 셸의 작업과 번호 목록
bg %11번 작업을 백그라운드에서 재개
fg %1다시 포그라운드로 가져오기
Ctrl+Z는 포그라운드 프로그램을 일시 중단합니다(bg나 fg를 실행할 때까지 멈춤).
./long-export.sh > export.log 2>&1 &시작하고 바로 프롬프트로 돌아오기
wait스크립트에서 백그라운드 작업이 끝날 때까지 기다리기
nohup ./server > server.log 2>&1 &SSH 세션을 닫아도 유지
오래 실행할 것이라면 systemd 서비스(서비스와 로그 참고)나 tmux가 더 안정적입니다.
disown -h %1nohup을 깜빡했다면: bg로 백그라운드로 보낸 뒤 disown
tmux new -s deploy이름 있는 세션 시작
tmux attach -t deploySSH가 끊긴 뒤 다시 연결
패키지 관리자로 설치하세요. GNU screen은 오래된 대안입니다(분리는 Ctrl+A d, 다시 연결은 screen -r).
nice -n 19 tar -czf backup.tgz /data다른 작업을 방해하지 않는 백업
sudo renice -n -5 -p 1234실행 중인 프로세스의 우선순위 높이기
nice 값은 -20(가장 높은 우선순위)부터 19(가장 낮음)까지입니다. 0보다 낮게는 root만 설정할 수 있습니다.
timeout 30s curl -s https://example.com/health30초 후 포기
timeout -s KILL 5m ./job.sh5분 후 강제 종료
시간 제한에 걸리면 종료 상태 124로 끝납니다.
watch -n 2 df -h디스크 공간이 차는 것 지켜보기
watch -d 'ss -s'-d는 바뀐 부분을 강조
sudo lsof -i :80808080 포트에서 수신 대기 중인 것
sudo lsof +L1삭제됐지만 아직 열려 있는 파일(디스크는 꽉 찼는데 du에는 안 보일 때)
lsof -p 1234한 프로세스가 연 모든 파일
sudo fuser -vm /mnt/usbumount가 "target is busy"라고 하는 이유
sudo fuser -v 8080/tcpTCP 포트를 쓰는 프로세스
위험: fuser -k는 대상을 쓰는 모든 프로세스를 확인 없이 종료합니다. 마운트 지점이라면 내 셸도 포함될 수 있습니다.
time ./build.shreal = 실제 경과 시간, user + sys = CPU 시간
strace -f -e trace=openat ./app 2>&1 | grep -v ENOENT실제로 어떤 파일을 여는가?
sudo strace -p 1234멈춘 프로세스가 어디서 막혔나?
OS 버전, 커널, CPU, 메모리, 하드웨어, 시간, 부하.
uname -r예: 6.8.0-45-generic
uname -m어떤 바이너리를 받을지: x86_64 또는 aarch64
cat /etc/os-releasesystemd 시대의 모든 배포판에 있는 NAME, VERSION_ID, ID
lsb_release -a설치되어 있다면 Debian/Ubuntu용 대안
macOS/BSD: macOS: sw_vers.
hostnamectl호스트 이름, OS, 커널, 가상화
sudo hostnamectl set-hostname web01컴퓨터 이름 바꾸기
uptime1, 5, 15분 평균 부하
부하는 실행 중이거나 대기 중인 프로세스 수입니다. CPU 수(nproc)와 비교하세요. 4코어에서 부하 4면 꽉 찬 상태입니다.
free -h"free"가 아니라 "available" 열을 보세요
macOS/BSD: macOS: vm_stat 또는 top -l 1 | grep PhysMem.
Linux는 남는 RAM을 디스크 캐시로 쓰므로 정상인 컴퓨터에서도 "free"가 낮게 보입니다. "available"이 프로그램이 실제로 더 쓸 수 있는 양입니다.
lscpu모델, 소켓, 코어, 스레드, 플래그
make -j"$(nproc)"사용 가능한 모든 코어 사용
macOS/BSD: macOS: sysctl -n hw.ncpu, sysctl -n machdep.cpu.brand_string.
lspci -k | grep -A3 -i vga그래픽 카드와 사용 중인 드라이버
lsusbUSB 장치가 인식은 되나?
sudo dmidecode -t memory | grep -i size슬롯별 설치된 RAM
sudo lshw -short장치마다 한 줄
sudo dmesg -T | tail -30방금 무슨 일이 있었나(USB 연결, 디스크 오류)
sudo dmesg -T | grep -i 'out of memory'OOM 킬러가 앱을 멈췄나?
grep MemAvailable /proc/meminfo사용 가능한 메모리(kB)
grep -c ^processor /proc/cpuinfo논리 CPU 수
cat /proc/1234/status프로세스 하나의 상태와 메모리
vmstat 1 5r = 실행 대기열, si/so = 스와핑, wa = I/O 대기
iostat -xz 1디스크별 사용률(%util)과 지연 시간(await)
iostat는 sysstat 패키지에 들어 있습니다.
date '+%Y-%m-%d %H:%M:%S'로그용 타임스탬프
date +%s1970-01-01 UTC 이후 초
date -d @1700000000타임스탬프를 날짜로(GNU)
date -d '2 days ago' +%F상대 날짜(GNU)
macOS/BSD: macOS date에는 -d가 없습니다. 타임스탬프는 date -r 1700000000, "2일 전"은 date -v-2d, 파싱은 date -j -f '%Y-%m-%d' 2026-10-18 +%s를 쓰세요.
timedatectl현지 시간, UTC, 시간대, NTP 동기화 여부
timedatectl list-timezones | grep America시간대 이름 찾기
sudo timedatectl set-timezone America/Toronto시간대 바꾸기
여유 공간, 공간을 차지하는 것, 파티션, 마운트, 포맷.
df -h마운트된 모든 파일 시스템
df -h .이 디렉터리가 있는 파일 시스템
df -i공간이 남았는데 "No space left"? inode가 바닥났을 수 있음
macOS/BSD: macOS에서 -T는 유형을 표시하는 게 아니라 유형으로 필터링합니다.
du -sh /var/log폴더 하나의 크기
du -h -d 1 | sort -h하위 폴더, 가장 큰 것이 마지막(GNU와 macOS 모두 작동)
sudo du -xh -d 1 / | sort -h | tail가장 큰 최상위 디렉터리
macOS/BSD: macOS du에는 -d는 있지만 --max-depth는 없습니다.
sudo ncdu -x /화살표로 이동, d로 삭제
apt install ncdu / dnf install ncdu로 설치하세요.
lsblk디스크, 파티션, 크기, 마운트 지점
lsblk -f어느 파티션이 ext4/xfs인지와 UUID
macOS/BSD: macOS: diskutil list.
sudo blkid /dev/sdb1/etc/fstab에 쓸 UUID와 TYPE
findmnt옵션을 포함한 마운트 트리
findmnt -T /var/lib/docker이 경로가 어느 파일 시스템에 있는지
sudo findmnt --verify재부팅 전에 /etc/fstab 오류 확인
sudo mount /dev/sdb1 /mnt/usbUSB 메모리 마운트(디렉터리가 있어야 함)
sudo mount -o remount,rw /읽기 전용 루트를 쓰기 가능하게
sudo mount -t nfs nas:/export /mnt/nasNFS 공유 마운트
sudo umount /mnt/usb이후에는 안전하게 뽑아도 됨
sudo umount -l /mnt/nas지연: 지금 분리하고, 사용이 끝나면 정리
"target is busy"는 어떤 프로세스(흔히 그 디렉터리에 있는 내 셸)가 사용 중이라는 뜻입니다. fuser -vm이나 lsof로 찾으세요.
UUID=3f6c... /data ext4 defaults,nofail 0 2파일 시스템마다 한 줄. nofail은 디스크가 없어도 부팅을 계속하게 함
sudo mount -afstab의 모든 항목을 지금 마운트: 재부팅 전에 테스트
fstab에 오타가 있으면 다음 부팅 때 응급 모드로 들어갈 수 있습니다. 편집한 뒤에는 꼭 sudo mount -a(또는 findmnt --verify)를 실행하세요.
sudo fdisk -l모든 디스크와 파티션
sudo parted /dev/sdb print파티션 테이블 유형(gpt/msdos)과 배치
위험: 파티션 테이블을 쓰면(fdisk의 w, parted의 mklabel) 그 디스크의 기존 데이터에 접근할 수 없게 됩니다. 먼저 lsblk로 장치 이름을 확인하세요. /dev/sda와 /dev/sdb는 쉽게 뒤바뀝니다.
sudo mkfs.ext4 -L data /dev/sdb1레이블을 붙인 ext4
sudo mkfs.vfat -F 32 /dev/sdc1다른 기기에서도 읽을 수 있는 USB 메모리용 FAT32
위험: 대상의 파일 시스템을 즉시 지우며, 장치가 마운트되어 있지 않으면 확인도 하지 않습니다. lsblk -f로 장치를 확인하세요. /dev/sda1 대신 /dev/sda를 포맷하거나 디스크를 잘못 고르면 전부 날아갑니다.
sudo fsck -f /dev/sdb1마운트 해제된 파티션을 강제로 전체 검사
위험: 읽기/쓰기로 마운트된 파일 시스템에는 절대 fsck를 실행하지 마세요. 손상될 수 있습니다. 먼저 마운트를 해제하거나, 루트 파일 시스템이라면 복구 미디어로 부팅하세요.
sudo dd if=ubuntu.iso of=/dev/sdX bs=4M status=progress conv=fsync부팅 USB 만들기(sdX는 파티션이 아니라 디스크 전체로 바꾸세요)
dd if=/dev/zero of=test.img bs=1M count=100100MB 파일 만들기
위험: dd는 묻지 않고 of= 대상을 덮어씁니다. if=와 of=를 바꿔 쓰거나 /dev/sdX를 잘못 고르면 그 디스크가 지워집니다. 실행 직전에 lsblk로 확인하세요.
macOS/BSD: macOS: diskutil unmountDisk 후 /dev/rdiskN(diskutil list에서 확인)을 대상으로 하고, bs=4m을 쓰며, 진행 상황은 Ctrl+T로 봅니다.
sync && sudo umount /mnt/usbUSB 드라이브를 뽑기 전에
swapon --show현재 스왑
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile2GB 스왑 파일 추가(유지하려면 /etc/fstab에 추가)
Btrfs에서 스왑 파일을 쓰려면 추가 단계가 필요합니다(최신 btrfs-progs에서는 btrfs filesystem mkswapfile).
shred -u -n 3 secrets.txt세 번 덮어쓴 뒤 삭제
위험: 되돌릴 수 없습니다. 또한 SSD, 저널링이나 copy-on-write 파일 시스템(Btrfs, ZFS), 스냅숏이 있는 환경에서는 믿을 수 없습니다. 제대로 보호하려면 전체 디스크 암호화를 쓰세요.
IP 주소, 라우팅, 열린 포트, HTTP 요청, DNS, SSH, 파일 전송.
ip -br a인터페이스마다 한 줄: 이름, 상태, 주소
ip a show eth0인터페이스 하나를 자세히
hostname -IIP 주소만
macOS/BSD: macOS: ifconfig 또는 ipconfig getifaddr en0.
ip는 많은 배포판에서 더 이상 설치하지 않는 예전 ifconfig(net-tools)를 대체합니다.
ip r경로. "default via"가 게이트웨이
ip route get 1.1.1.1목적지가 어떤 인터페이스와 게이트웨이를 쓰는지
sudo ip route add 10.20.0.0/16 via 192.168.1.1경로 추가(재부팅하면 사라짐)
ip link인터페이스와 MAC 주소
sudo ip link set eth0 down && sudo ip link set eth0 up인터페이스 껐다 켜기
위험: SSH로 접속 중인 인터페이스를 끄면 세션이 끊깁니다.
sudo ss -tulpn모든 수신 대기 포트와 프로그램
ss -tn state established '( dport = :443 )'443 포트로 연결된 세션
ss -s연결 합계
macOS/BSD: macOS: lsof -iTCP -sTCP:LISTEN -n -P 또는 netstat -an.
ss는 netstat를 대체합니다. net-tools가 설치된 곳에서는 netstat -tulpn도 여전히 작동합니다.
curl -I https://example.com상태 줄과 헤더
curl -LO https://example.com/file.tar.gz리디렉션을 따라가며 다운로드
curl -s -o /dev/null -w '%{http_code}\n' https://example.com상태 코드만
curl -fsSL https://example.com/install.sh -o install.sh실행하기 전에 읽어 볼 스크립트 다운로드
curl -H 'Content-Type: application/json' -d '{"name":"Ada"}' https://api.example.com/usersJSON POST
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/me$TOKEN이 확장되도록 큰따옴표 사용
curl -X DELETE https://api.example.com/users/42다른 메서드
wget -c https://example.com/big.iso연결이 끊긴 뒤 이어받기
wget -qO- https://example.com/data.json | jq .다른 명령어로 바로 파이프
macOS/BSD: 기본 macOS에는 없습니다. curl -LO를 쓰세요(이어받기는 curl -C - -LO).
dig +short example.comA 레코드만
dig MX example.com메일 서버
dig @1.1.1.1 example.com특정 리졸버에 질의(로컬 캐시 우회)
dig -x 8.8.8.8역방향 조회
dig +trace example.com루트부터 위임 경로 추적
패키지 이름: dnsutils(Debian/Ubuntu) 또는 bind-utils(Fedora/RHEL).
host example.comA, AAAA, MX를 짧은 답 하나로
nslookup example.com 8.8.8.8Windows에도 같은 명령어가 있음
resolvectl status인터페이스별 DNS 서버
sudo resolvectl flush-cachessystemd-resolved 캐시 비우기
macOS/BSD: macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder.
systemd-resolved를 쓰는 시스템에서만(Ubuntu, Fedora 기본값).
ping -c 4 example.com패킷 4개 후 요약
Linux와 macOS에서 ping은 -c를 주지 않으면 Ctrl+C를 누를 때까지 계속됩니다(Windows는 4번 후 멈춤). 응답이 없다고 꼭 다운된 것은 아닙니다. 많은 호스트가 ICMP를 차단합니다.
traceroute -n example.comDNS 조회 없이 홉 표시
tracepath example.comroot 권한 불필요, MTU도 표시
macOS/BSD: macOS에는 traceroute는 있지만 tracepath는 없습니다.
Linux에서는 traceroute를 따로 설치해야 할 수 있지만, tracepath(iputils)는 보통 있습니다.
mtr -rw -c 100 example.com홉마다 100번 측정 후 보고서
ping과 traceroute를 합친 도구입니다. 중간 홉 하나에서만 손실이 보이면 보통 그 라우터가 ICMP 우선순위를 낮춘 것이고, 끝까지 이어지는 손실이 진짜입니다.
ssh alice@203.0.113.10로그인
ssh -p 2222 alice@host표준이 아닌 포트
ssh alice@host 'df -h'명령어 하나만 실행하고 돌아오기
ssh -J bastion.example.com alice@10.0.0.5배스천 호스트를 거쳐 접속
ssh -N -L 5432:localhost:5432 alice@db-host로컬 DB 클라이언트를 원격 Postgres에 연결
ssh -N -D 1080 alice@host서버를 거쳐 웹 브라우징
ssh-keygen -t ed25519 -C "you@example.com"~/.ssh에 새 키 쌍 생성
ssh-copy-id alice@host공개 키를 서버의 authorized_keys에 추가
ssh-keygen -R host서버를 다시 만든 뒤 예전 호스트 키 제거("REMOTE HOST IDENTIFICATION HAS CHANGED")
Host web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519이후에는 ssh web만 입력(scp와 rsync도 사용)
scp report.pdf alice@host:/tmp/업로드
scp alice@host:/var/log/app.log .다운로드
scp -r -P 2222 site/ alice@host:~/다른 포트로 폴더 업로드
OpenSSH 9.0부터 scp는 내부적으로 SFTP 프로토콜을 씁니다. 크거나 반복되는 복사에는 변경분만 보내는 rsync가 더 빠릅니다.
rsync -avzP site/ deploy@host:/srv/site/site/ 끝의 슬래시는 폴더 자체가 아니라 내용을 복사
rsync -av --exclude 'node_modules' ./ /backup/app/불필요한 것 없이 로컬 백업
macOS/BSD: 최신 macOS에는 rsync 대신 openrsync가 들어 있습니다. 흔한 플래그는 작동하지만 드문 플래그 중에는 안 되는 것도 있습니다.
src/는 "src의 내용", 슬래시 없는 src는 "src 폴더"를 뜻합니다. 이를 틀리면 폴더가 중첩됩니다(dest/src/…).
rsync -avn --delete site/ /srv/site/먼저 시험 실행: "deleting"으로 시작하는 줄이 삭제될 항목
rsync -av --delete site/ /srv/site/그다음 실제 실행
위험: 원본에 없는 것은 dest에서 모두 삭제합니다. 원본과 대상을 바꿔 쓰거나 원본 경로가 비었거나 틀리면 대상이 지워집니다. 항상 먼저 -n으로 실행하세요.
nc -zv db.internal 5432"succeeded" 또는 "Connection refused"/시간 초과
nc -l 9000포트에서 수신 대기해 반대편에서 방화벽 테스트
netcat 종류마다 플래그가 다릅니다. 전통적인 버전은 nc -l -p 9000이 필요합니다.
sudo ufw status verbose규칙과 기본 정책
sudo ufw allow 22/tcpSSH 허용(enable 전에 하세요)
sudo ufw allow from 10.0.0.0/8 to any port 5432포트 하나, 네트워크 하나
위험: 원격 서버에서 SSH를 먼저 허용하지 않고(ufw allow OpenSSH 또는 22/tcp) sudo ufw enable을 실행하면 접속이 막힙니다.
sudo firewall-cmd --list-all활성 영역과 규칙
sudo firewall-cmd --permanent --add-service=https && sudo firewall-cmd --reloadHTTPS 영구 개방
sudo firewall-cmd --permanent --add-port=8080/tcp포트 개방
--permanent가 없으면 규칙은 다음 다시 불러오기나 재부팅까지만 유지됩니다.
nmcli device status인터페이스와 연결 여부
nmcli device wifi list주변 네트워크
nmcli device wifi connect 'MyWiFi' password 'secret'네트워크에 연결
주요 패키지 관리자 4종에서 같은 작업을 하는 방법: Debian/Ubuntu(apt), Fedora/RHEL(dnf), Arch(pacman), openSUSE(zypper). 시스템을 바꾸는 명령어에는 앞에 sudo를 붙이세요.
| 작업 | apt(Debian, Ubuntu) | dnf(Fedora, RHEL) | pacman(Arch) | zypper(openSUSE) |
|---|---|---|---|---|
| 패키지 목록 새로고침 # dnf는 메타데이터가 오래되면 자동으로 새로고칩니다. Arch에서는 pacman -Sy 뒤에 -S pkg를 실행하지 마세요. 부분 업그레이드는 지원되지 않으므로 -Syu를 쓰세요. | apt update | dnf makecache | pacman -Sy | zypper refresh |
| 전체 업그레이드 # openSUSE Tumbleweed는 zypper dup을 씁니다. apt full-upgrade는 업그레이드를 마치는 데 필요하면 패키지를 제거하기도 합니다. | apt update && apt upgrade | dnf upgrade | pacman -Syu | zypper update |
| 패키지 설치 # | apt install nginx | dnf install nginx | pacman -S nginx | zypper install nginx |
| 다운로드한 패키지 파일 설치 # ./는 apt에게 패키지 이름이 아니라 파일이라고 알려 주므로 의존성이 해결됩니다(dpkg -i는 해결하지 않음). | apt install ./app.deb | dnf install ./app.rpm | pacman -U app.pkg.tar.zst | zypper install ./app.rpm |
| 패키지 제거 # | apt remove nginx | dnf remove nginx | pacman -R nginx | zypper remove nginx |
| 설정 파일 / 사용하지 않는 의존성까지 제거 # | apt purge nginx && apt autoremove | dnf remove nginx && dnf autoremove | pacman -Rns nginx | zypper remove --clean-deps nginx |
| 패키지 검색 # | apt search keyword | dnf search keyword | pacman -Ss keyword | zypper search keyword |
| 패키지 세부 정보 보기 # | apt show nginx | dnf info nginx | pacman -Si nginx (installed: -Qi) | zypper info nginx |
| 설치된 패키지 목록 # | apt list --installed | dnf list --installed | pacman -Q | zypper search --installed-only |
| 사용 가능한 업데이트 목록 # | apt list --upgradable | dnf check-update | checkupdates (pacman-contrib) | zypper list-updates |
| 파일이 어느 패키지에 속하는지 확인 # 아직 설치되지 않은 파일: dnf provides /path, apt-file search path(apt-file 필요), pacman -F path. | dpkg -S /usr/bin/curl | rpm -qf /usr/bin/curl | pacman -Qo /usr/bin/curl | rpm -qf /usr/bin/curl |
| 패키지가 설치한 파일 목록 # | dpkg -L nginx | rpm -ql nginx | pacman -Ql nginx | rpm -ql nginx |
| 패키지를 현재 버전으로 고정 # DNF 4에서 versionlock을 쓰려면 versionlock 플러그인 패키지가 필요합니다. | apt-mark hold nginx | dnf versionlock add nginx | IgnorePkg = nginx in /etc/pacman.conf | zypper addlock nginx |
| 패키지 캐시 비우기 # | apt clean | dnf clean all | pacman -Sc | zypper clean |
내가 누구인지, 누가 로그인했는지, 그리고 계정 관리.
iduid, gid, 속한 모든 그룹
id alice다른 사용자
w누가 접속해 무엇을 실행 중인지
last -n 10최근 로그인과 재부팅
sudo lastb -n 10최근 로그인 실패(Linux)
sudo useradd -m -s /bin/bash alice && sudo passwd alice계정을 만들고 비밀번호 설정
Debian/Ubuntu에서는 adduser alice가 홈 디렉터리와 비밀번호까지 설정해 주는 더 친절한 대화형 래퍼입니다.
sudo usermod -aG docker alicealice가 docker를 실행할 수 있게
sudo usermod -aG sudo aliceDebian/Ubuntu에서 관리자 권한(Fedora/RHEL/Arch는 wheel 그룹)
위험: -a 없이 usermod -G를 쓰면 사용자의 보조 그룹이 모두 교체되어 sudo 권한이 사라질 수 있습니다. 그룹 변경은 다음 로그인부터 적용됩니다(또는 newgrp docker 실행).
sudo userdel -r olduser홈 디렉터리와 메일 스풀도 삭제
위험: -r은 홈 디렉터리와 파일을 영구 삭제합니다. 먼저 백업하거나, 대신 계정을 잠그세요(passwd -l).
passwd내 비밀번호 변경
sudo passwd alice다른 사람의 비밀번호 재설정
sudo passwd -l alice비밀번호 로그인 잠금(SSH 키는 여전히 작동할 수 있음)
sudo groupadd developers새 그룹
sudo gpasswd -d alice developers그룹에서 alice 제거
groups alicealice의 그룹
getent group sudosudo 그룹 구성원(LDAP에서도 작동)
getent passwd alice계정 항목: UID, 홈, 셸
sudo visudo -f /etc/sudoers.d/deploy규칙마다 별도 파일
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp비밀번호 없이 명령어 하나 허용
visudo는 저장 전에 문법을 검사합니다. 일반 편집기로 /etc/sudoers를 고치다 오타가 나면 모두가 sudo를 못 쓰게 될 수 있습니다.
sudo chage -l alice마지막 변경일과 만료일
sudo chage -M 90 alice90일마다 만료
tar, gzip, xz, zip, 체크섬.
tar -czf site-2026-10-18.tar.gz site/폴더를 gzip 압축 아카이브로
tar -cJf logs.tar.xz --exclude='*.tmp' logs/임시 파일을 빼고 더 작은 xz 아카이브로
tar -xf archive.tar.gzGNU tar와 macOS tar는 압축 방식을 스스로 감지
tar -xzf app.tar.gz -C /opt/app --strip-components=1감싸는 디렉터리 없이 폴더 안에
tar -tf backup.tar.gz | less풀지 않고 내용 보기
tar -xf backup.tar.gz etc/nginx/nginx.conf파일 하나만 꺼내기(-t로 보이는 경로)
tar --zstd -cf data.tar.zst data/xz보다 훨씬 빠르고, 압축률은 gzip -9와 비슷하거나 더 좋음
zstd -d file.zst파일 하나 압축 해제
GNU tar 1.31 이상(또는 최신 bsdtar)과 zstd 프로그램이 필요합니다.
gzip -k access.logaccess.log.gz를 만들고 원본 유지
zcat access.log.gz | grep 404디스크에 풀지 않고 읽기
zgrep 500 access.log.*.gz로테이션된 로그를 바로 grep
-k가 없으면 gzip은 원본 파일을 .gz 버전으로 바꿉니다.
xz -T0 -k big.sql모든 CPU 코어 사용, 원본 유지
unxz big.sql.xz압축 해제
zip -r site.zip site/폴더 압축
zip -r site.zip site/ -x '*.git*' '*/node_modules/*'경로 제외
zip -e는 취약한 구식 ZipCrypto 방식으로 암호화합니다. 제대로 보호하려면 7z나 gpg를 쓰세요.
unzip files.zip -d files/폴더 안에
unzip -l files.zip내용 목록만
unzip -o files.zip묻지 않고 덮어쓰기
7z x archive.7z전체 경로를 유지하며 풀기
7z a -p backup.7z docs/AES-256 암호화 아카이브(비밀번호를 물어봄)
7z l archive.rar여러 형식의 내용 목록
패키지: Debian/Ubuntu는 p7zip-full / 7zip, Fedora/Arch는 p7zip 또는 7zip.
sha256sum ubuntu.iso다운로드 페이지의 해시와 비교
sha256sum -c SHA256SUMS --ignore-missing목록 중 실제로 가진 파일만 모두 확인
macOS/BSD: macOS: shasum -a 256 file(그리고 shasum -a 256 -c SUMSFILE).
split -b 100M backup.tar.gz backup.part.backup.part.aa, .ab, …
cat backup.part.* > backup.tar.gz다시 합치기
이름, 날짜, 크기로 파일을 찾고, 파일 안의 텍스트를 찾습니다.
find . -name '*.log'셸이 먼저 확장하지 않도록 패턴을 따옴표로 묶기
find / -iname 'nginx.conf' 2>/dev/null모든 곳을 검색하고 권한 오류 숨기기
find . -maxdepth 1 -type d바로 아래 하위 디렉터리
find . -type l -xtype l깨진 심볼릭 링크(GNU)
find . -type f -empty빈 파일
find /var/log -type f -mtime +3030일이 지난 로그
find . -type f -mmin -15최근 15분 동안 바뀐 것
sudo find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null루트 파일 시스템에서 500MB가 넘는 파일
find . -name '*.sh' -exec chmod +x {} +{} +는 명령어 한 번에 여러 파일을 넘김(빠름)
find . -name '*.py' -exec grep -l 'TODO' {} +TODO가 들어 있는 Python 파일
find . -name '*.jpg' -print0 | xargs -0 -P4 -n 20 jpegoptim병렬 처리, 이름에 공백이 있어도 안전
find /tmp/app -name '*.tmp' -mtime +7 -print1단계: 일치하는 것 목록 보기
find /tmp/app -name '*.tmp' -mtime +7 -delete2단계: 같은 명령어 끝에 -delete
위험: 순서가 중요합니다. -delete는 나타난 위치에서 실행되므로 find . -delete -name "*.tmp"는 이름 검사를 하기도 전에 . 아래의 모든 것을 삭제합니다. -delete는 맨 끝에 두고, 먼저 -print로 실행하세요.
find /srv -type f -perm -o+w누구나 쓸 수 있는 파일
sudo find / -xdev -perm -4000 -type f 2>/dev/nullsetuid 프로그램
locate -i nginx.conffind /보다 훨씬 빠름
sudo updatedb지금 색인 새로고침
plocate나 mlocate가 제공합니다. 색인은 매일 다시 만들어지므로 오늘 만든 파일은 updatedb가 실행될 때까지 안 보일 수 있습니다.
grep -n 'ERROR' app.log일치하는 줄과 번호
grep -v '^#' nginx.conf | grep -v '^$'주석과 빈 줄을 뺀 설정
grep -c 'Failed password' /var/log/auth.logSSH 로그인 실패 횟수
grep -rn 'TODO' src/모든 TODO를 파일과 줄 번호와 함께
grep -rl --include='*.php' 'mysql_connect' .아직 예전 API를 쓰는 PHP 파일
grep -rn --exclude-dir={.git,node_modules} 'apiKey' .불필요한 폴더 건너뛰기
grep -C 3 'Traceback' app.log앞뒤 3줄
grep -A 20 'Exception' app.log오류 뒤의 스택 트레이스
grep -E 'error|warn' app.log두 단어 중 하나(확장 정규식)
grep -Eo '[0-9]{1,3}(\.[0-9]{1,3}){3}' access.log | sort | uniq -c | sort -rn | head로그에서 가장 많이 나온 IP 주소
grep -P '\d{4}-\d{2}-\d{2}' filePerl 스타일 \d(GNU grep)
macOS/BSD: -E는 어디서나 작동하지만, -P(PCRE)는 GNU 기능이라 macOS 버전에 따라 없을 수 있습니다.
type ll별칭, 함수, 내장 명령어, 파일 중 무엇인지 알려 줌
command -v docker >/dev/null || echo "docker missing"스크립트에서 쓰는 이식성 있는 확인
which -a python3PATH에 있는 모든 python3를 순서대로
텍스트와 JSON을 자르고, 거르고, 정렬하고, 세고, 변환하고, 재구성합니다.
sed 's/http:/https:/g' links.txt결과만 출력하고 파일은 그대로
sed 's|/usr/local|/opt|g' paths.txt구분자는 아무 문자나 가능, 경로에 편리
sed -E 's/([0-9]+)px/\1rem/g' style.css캡처한 그룹 재사용
sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_configGNU sed
sed -i.bak 's/foo/bar/g' config.iniconfig.ini.bak을 남김. GNU와 macOS 모두 작동
macOS/BSD: macOS sed는 -i 뒤에 인수가 필요합니다: sed -i '' 's/foo/bar/g' file. GNU sed는 ''를 스크립트로 읽으므로 양쪽에서 모두 되는 형태는 -i.bak뿐입니다.
sed -n '100,120p' big.log100~120번째 줄
sed '/^\s*#/d; /^$/d' app.conf주석과 빈 줄 제거(GNU \s)
sed -n '/BEGIN CERT/,/END CERT/p' bundle.pem두 표시 사이의 모든 내용
awk '{print $1}' access.log첫 번째 열(클라이언트 IP)
awk -F: '{print $1, $7}' /etc/passwd사용자와 셸
awk -F, 'NR>1 {print $2}' data.csvCSV 두 번째 열, 헤더 건너뛰기(따옴표 안 쉼표가 없는 단순 CSV만)
awk '$9 >= 500' access.log9번째 필드(상태)가 5xx인 줄
awk '{s += $2} END {print s}' sales.txt2번째 열의 합계
awk '{c[$1]++} END {for (k in c) print c[k], k}' access.log | sort -rn | head값별 개수, 상위 10개
cut -d, -f1,3 data.csv1번째와 3번째 열
cut -d: -f1 /etc/passwd모든 사용자 이름
cut -c1-10 file각 줄의 처음 10글자
cut은 구분자마다 필드를 나누므로 공백 두 개는 빈 필드가 됩니다. 공백으로 정렬된 출력에는 awk를 쓰세요.
du -sh * | sort -h크기순 폴더
sort -t, -k3,3nr data.csvCSV를 3번째 열 기준 숫자 내림차순으로
sort -u emails.txt > unique.txt정렬하고 중복 제거
sort ips.txt | uniq -c | sort -rn | head가장 자주 나오는 줄 상위 10개
uniq는 인접한 중복만 합치므로 먼저 정렬하세요.
wc -l access.log줄 수
ls | wc -l이 폴더의 항목 수
grep -c '' file줄바꿈 없는 마지막 줄까지 포함한 줄 수
tr 'a-z' 'A-Z' < in.txt대문자로
tr -d '\r' < windows.txt > unix.txtWindows CRLF 줄 끝 제거
tr -s ' ' < file연속된 공백 줄이기
tr '\n' ',' < list.txt줄을 쉼표로 이어 붙이기
tr은 표준 입력만 읽으므로 <로 파일을 넘기세요.
find . -name '*.log' -print0 | xargs -0 rm -f찾은 파일을 안전하게 삭제
cat urls.txt | xargs -n 1 -P 4 curl -sO한 번에 4개씩 다운로드
ls *.png | xargs -I {} cp {} /backup/{}항목마다 명령어 하나
macOS/BSD: GNU xargs는 -r을 주지 않으면 입력이 비어 있어도 명령어를 한 번 실행합니다. macOS xargs는 기본으로 빈 입력을 건너뛰며 호환성을 위해 -r도 받습니다.
jq . response.json보기 좋게 출력
jq -r '.items[].name' data.json한 줄에 이름 하나
jq -r '.[] | select(.active) | .email' users.json거른 다음 필드 고르기
curl -s https://api.github.com/repos/jqlang/jq | jq '.stargazers_count'API에서 바로
apt/dnf install jq로 설치하세요. 최신 macOS에는 기본 포함되어 있습니다.
paste -sd, ids.txt모든 줄을 쉼표로 이어 붙이기
paste names.txt emails.txt두 파일을 두 열로
comm -12 <(sort a.txt) <(sort b.txt)양쪽 모두에 있음
comm -23 <(sort a.txt) <(sort b.txt)a.txt에만 있음
seq 1 51부터 5까지 한 줄에 하나씩
seq -w 1 100 채우기: 01 … 10
for i in $(seq 1 3); do echo "run $i"; done반복문 카운터
printf '%s' 'user:pass' | base64인코딩(printf는 끝 줄바꿈을 붙이지 않음)
echo dXNlcjpwYXNz | base64 -d디코딩
base64 -w 0 image.png > image.b64줄바꿈 없이(GNU는 76자에서 줄바꿈)
macOS/BSD: macOS base64는 기본으로 줄바꿈하지 않으며 -w가 없습니다. 디코딩은 -d를 쓰세요(예전 macOS는 -D).
iconv -f WINDOWS-1252 -t UTF-8 old.csv > new.csvExcel에서 내보낸 파일의 글자 깨짐 고치기
iconv -l지원하는 인코딩 목록
shuf -n 1 names.txt무작위 줄 하나
shuf -i 1-100 -n 51~100 중 무작위 숫자 5개
systemd 서비스: 시작, 중지, 부팅 시 사용 설정, journalctl로 로그 읽기.
systemctl status nginx상태, PID, 메모리, 마지막 로그 줄
systemctl is-active --quiet nginx && echo up스크립트용
sudo systemctl restart nginx완전히 다시 시작
sudo systemctl reload nginx연결을 끊지 않고 설정 다시 읽기(서비스가 지원하는 경우)
가능하면 다시 시작하기 전에 설정을 테스트하세요(예: sudo nginx -t). 오타 하나로 사이트가 내려가는 일을 막을 수 있습니다.
sudo systemctl enable --now docker부팅 시 사용 설정하고 지금 시작
sudo systemctl disable --now cups지금 중지하고 부팅 시에도 시작 안 함
sudo systemctl mask bluetooth아예 시작되지 못하게 차단(되돌리려면 unmask)
systemctl --failed무엇이 고장 났나
systemctl list-units --type=service --state=running무엇이 실행 중인가
systemctl list-unit-files --state=enabled부팅 시 무엇이 시작되나
sudo systemctl edit nginx패키지 업그레이드 후에도 유지되는 드롭인 오버라이드
systemctl cat nginx유닛과 모든 오버라이드
sudo systemctl daemon-reload유닛 파일을 직접 수정한 뒤 필요
[Unit]
Description=My app
After=network.target
[Service]
User=app
WorkingDirectory=/srv/app
ExecStart=/srv/app/bin/server
Restart=on-failure
[Install]
WantedBy=multi-user.target그다음: sudo systemctl daemon-reload && sudo systemctl enable --now myapp
journalctl -u nginx -f서비스 하나 따라가기
journalctl -u myapp --since '10 min ago'최근 구간
journalctl -b -1 -p err충돌 전 부팅의 오류
journalctl --disk-usage로그가 차지하는 공간
sudo journalctl --vacuum-size=500M보관된 로그를 최대 500MB로 유지
sudo journalctl --vacuum-time=14d2주보다 오래된 보관 로그 삭제
영구 제한은 /etc/systemd/journald.conf에서 SystemMaxUse=로 설정하세요.
sudo tail -f /var/log/syslogDebian/Ubuntu의 일반 로그(Fedora/RHEL은 /var/log/messages)
sudo tail -f /var/log/auth.logDebian/Ubuntu의 로그인과 sudo 기록(RHEL은 /var/log/secure)
일부 배포판(Fedora, Arch)은 rsyslog가 설치되어 있지 않으면 로그를 저널에만 보관합니다.
sudo reboot지금 재부팅
sudo shutdown -r +10 'Kernel update'로그인한 사용자에게 알리고 10분 후 재부팅
sudo shutdown -c예약된 종료 취소
sudo shutdown -h now전원 끄기
명령어를 일정에 맞춰 실행하거나 나중에 한 번 실행합니다.
crontab -e$EDITOR로 crontab 열기
crontab -l목록 보기
crontab -l > crontab.bak백업
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1매일 02:30, 출력 보관
*/15 * * * * /usr/local/bin/check.sh15분마다
0 9 * * 1-5 /usr/local/bin/report.sh월요일~금요일 09:00
@reboot /usr/local/bin/startup.sh부팅 시 한 번
cron은 최소한의 PATH로, 셸 프로필 없이 실행됩니다. 절대 경로를 쓰세요. 명령어 안의 %는 \%로 이스케이프해야 합니다.
crontab -l > ~/crontab.bak && crontab -r삭제 전에 백업
crontab ~/crontab.bak파일에서 복원
위험: 확인 없이 내 cron 작업을 모두 삭제하며, 키보드에서 r은 e 바로 옆에 있습니다. 일부 cron 구현은 먼저 묻는 -i를 지원합니다(crontab -ri).
0 3 * * * root /usr/local/bin/cleanup.sh/etc/cron.d/cleanup의 한 줄: 사용자 필드가 추가로 있음에 주의
ls /etc/cron.daily/run-parts가 하루 한 번 실행하는 스크립트
Debian과 Ubuntu에서는 /etc/cron.d 안의 파일 중 이름에 점이 들어간 것은 무시되므로, backup.cron이 아니라 backup으로 이름 지으세요.
echo 'systemctl restart myapp' | sudo at 02:00오늘 밤 새벽 2시
echo './report.sh' | at now + 30 minutes30분 후
atq대기 중인 작업
atrm 33번 작업 취소
at 패키지와 실행 중인 atd 서비스가 필요합니다.
systemctl list-timers모든 타이머와 다음 실행 시각
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.targetbackup.service 옆에 backup.timer. Persistent는 꺼져 있던 동안 놓친 실행을 따라잡음
systemd-analyze calendar 'Mon..Fri 09:00'OnCalendar 표현식의 의미 확인
sleep 5 && curl -s localhost:8080/health서비스가 시작될 시간 주기
sleep 2m단위 접미사는 GNU와 현재 macOS에서 작동
파이프, 리디렉션, 글로빙, 변수, 기록, 그리고 시간을 가장 많이 아껴 주는 키. macOS는 기본으로 zsh를 쓰며, shopt, help, bash 4 기능(macOS에는 bash 3.2가 들어 있음)을 빼면 거의 모두 그대로 작동합니다.
ps aux | grep nginx목록 거르기
history | grep 'docker run'예전에 실행한 명령어 찾기
set -o pipefail스크립트에서: 마지막뿐 아니라 어느 부분이든 실패하면 파이프라인 전체가 실패
ls -l > listing.txt덮어쓰기(파일 생성)
echo 'done' >> progress.log덧붙이기
set -o noclobber>가 기존 파일을 덮어쓰지 않게(>|는 강제)
셸은 명령어를 실행하기 전에 파일을 비우므로 sort file > file은 빈 파일만 남깁니다. 새 이름으로 쓴 뒤 mv하세요.
find / -name x 2>/dev/null오류 메시지 버리기
./build.sh > build.log 2>&1출력과 오류를 한 파일에(순서 중요: > 먼저, 그다음 2>&1)
./build.sh &> build.log같은 기능의 bash 축약형
mysql mydb < dump.sql파일을 입력으로
cat > config.yml <<'EOF'
port: 8080
host: $HOST stays literal
EOF'EOF'를 따옴표로 묶으면 $변수가 확장되지 않음
grep -c a <<< "banana"히어 스트링
make && sudo make install빌드가 성공했을 때만 설치
cd /srv/app || exit 1cd가 실패하면 스크립트 중단
(cd frontend && npm run build)괄호: 서브셸이라 현재 디렉터리가 바뀌지 않음
echo "Today is $(date +%A)"명령어 치환
echo $(( 1024 * 4 ))정수 산술
diff <(ls dir1) <(ls dir2)프로세스 치환: 출력을 임시 파일처럼
백틱 `command`는 $(command)의 옛 형태입니다. $( )는 중첩할 수 있고 읽기 쉽습니다.
ls *.jpg이 폴더의 모든 JPG
rm photo-??.pngphoto-01.png … photo-99.png
cp config.{yml,yml.bak}중괄호 확장: cp config.yml config.yml.bak
shopt -s globstar; ls **/*.md**는 모든 깊이와 일치(bash 4 이상)
글로브는 기본으로 점 파일과 일치하지 않습니다(shopt -s dotglob로 변경). 일치하는 것이 없으면 shopt -s nullglob가 설정되지 않은 한 bash는 패턴을 그대로 넘깁니다.
echo 'Cost: $5'작은따옴표: 아무것도 확장되지 않음
echo "Home is $HOME"큰따옴표: 변수는 확장되고 공백은 유지
cp "$file" "$dest/"경로가 든 변수는 항상 따옴표로: 따옴표가 없으면 공백 때문에 깨짐
name="Ada"; echo "Hi $name"설정하고 사용
echo "${PORT:-8080}"설정되지 않았거나 비어 있을 때 기본값
file=report.tar.gz; echo "${file%%.*}" "${file##*/}"확장자 제거 / 디렉터리 제거
echo "${#name}"문자열 길이
export NODE_ENV=production이 셸에서 시작하는 모든 프로그램에 보임
DEBUG=1 ./app그 명령어 하나에만
printenv | sort목록 보기
unset DEBUG삭제
셸이 끝나면 사라집니다. 유지하려면 export를 ~/.bashrc(대화형 셸)나 ~/.profile(로그인 셸)에 넣으세요.
echo "$PATH" | tr : '\n'한 줄에 항목 하나
export PATH="$HOME/.local/bin:$PATH"내 bin 폴더를 앞에 추가(~/.bashrc에 추가)
hash -r바이너리를 옮긴 뒤 캐시된 명령어 위치 잊기
alias ll='ls -alF'유지하려면 ~/.bashrc에 추가
source ~/.bashrc새 터미널을 열지 않고 변경 적용(. ~/.bashrc와 같음)
\ls별칭을 우회해 진짜 ls 실행
grep -q root /etc/passwd; echo $?0 찾음, 1 못 찾음, 2 오류
set -euo pipefail스크립트 맨 위: 오류, 설정되지 않은 변수, 실패한 파이프에서 중단
sudo !!마지막 명령어를 sudo로 다시 실행
cd !$이전 명령어의 마지막 인수 사용
!42기록의 42번째 줄 다시 실행
^foo^bar마지막 명령어에서 foo를 bar로 바꿔 다시 실행
HISTCONTROL=ignorespace(Ubuntu에서는 ignoreboth의 일부로 기본값)이면 앞에 공백을 넣고 입력한 명령어는 저장되지 않습니다. 비밀 정보가 든 명령어에 유용합니다.
bind -P | less모든 키 바인딩 목록
man rsync전체 매뉴얼. /로 검색, q로 종료
man 5 crontab섹션 5: 명령어가 아니라 파일 형식
help cdbash 내장 명령어에는 별도 man 페이지가 없음
apropos partition어떤 명령어가 그 단어를 언급하는지
#!/usr/bin/env bash
set -euo pipefail
name="${1:-world}"
if [[ -f "$name.txt" ]]; then
echo "found $name.txt"
fi
for f in *.log; do
echo "$f"
done인수, 조건 검사, 반복문
chmod +x script.sh && ./script.sh Ada실행 가능하게 만들고 실행
bash -x script.sh실행되는 줄을 하나씩 추적
$1 … $9는 인수, "$@"는 전체 인수, $#는 인수 개수입니다. [[ ]]는 bash 문법이므로 POSIX sh 스크립트에서는 [ ]를 쓰세요.
reset바이너리 파일을 cat한 뒤 터미널에 이상한 문자가 나올 때
문제를 발견하셨거나 개선할 점이 있나요? 모든 메시지를 읽고 빠르게 고칩니다.
이 Linux 명령어 치트 시트는 200개가 넘는 명령어를 하려는 작업별로 묶었습니다. 디렉터리 이동과 파일 관리, 권한, 프로세스, 디스크 공간, 네트워크, 패키지, 사용자, 압축 파일, 검색, 텍스트 처리, systemd 서비스와 로그, cron, 그리고 이 모든 것을 이어 주는 bash 기초까지 다룹니다. 각 항목에는 문법, 실제로 쓰게 될 옵션과 한 줄 설명, 복사 가능한 예시, 필요한 경우 경고가 있습니다. 작업(“디스크 여유 공간”, “8080 포트를 쓰는 프로세스”)이나 명령어 이름으로 검색하고, 원하는 항목에 바로 링크하세요.
옵션은 Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE가 탑재하는 GNU coreutils, util-linux, procps-ng, iproute2, systemd, bash 매뉴얼을 따릅니다. macOS에서 다르게 동작하는 부분은 파란 메모로 설명합니다. sed -i, date -d, stat -c, xargs는 한쪽에서 쓴 스크립트가 다른 쪽에서 깨지는 대표적인 지점이기 때문입니다. 이 시트는 자주 쓰는 90%를 위한 참고 자료일 뿐 man 페이지를 대신하지는 않습니다. 드물게 쓰는 옵션은 여전히 man <command>가 정답입니다.
이동과 파일부터 시작하세요: pwd, ls, cd, mkdir, cp, mv, rm, cat, less. 그다음 man(도움말), sudo, 검색용 grep과 find, 권한용 chmod와 chown, 프로세스용 ps, top, kill, 디스크 공간용 df와 du, 원격 접속용 ssh와 scp입니다. 파이프(|)와 리디렉션(>, >>)은 일찍 배우세요. 나머지 모든 것을 조합할 수 있게 해 줍니다.
df -h를 실행하면 마운트된 모든 파일 시스템의 여유 공간을 읽기 쉬운 단위로 볼 수 있습니다. 무엇이 공간을 차지하는지 찾으려면 디렉터리 안에서 du -h -d 1 | sort -h를 실행하세요. 하위 폴더를 가장 큰 것이 마지막에 오도록 나열합니다. df는 디스크가 가득 찼다는데 du로 아무것도 찾을 수 없다면, 삭제된 파일을 프로세스가 아직 열고 있을 가능성이 높습니다. sudo lsof +L1로 확인할 수 있습니다.
sudo ss -tulpn을 실행하면 수신 대기 중인 모든 TCP·UDP 포트와 이를 소유한 프로그램이 나열되고, 포트 하나만 보려면 sudo lsof -i :8080을 쓰세요. sudo가 중요합니다. 없으면 내 프로세스의 이름만 보입니다. ss는 netstat을 대체했으며, netstat은 net-tools 패키지가 설치된 시스템에서 여전히 작동합니다.
kill PID는 SIGTERM을 보내 프로세스에 종료를 요청하고 정리할 기회를 줍니다. 파일을 플러시하고, 잠금을 해제하고, 연결을 닫을 수 있습니다. kill -9 PID는 SIGKILL을 보내는데, 커널이 즉시 강제하며 프로세스가 가로채거나 무시할 수 없으므로 정리가 전혀 이루어지지 않습니다. 먼저 일반 kill을 쓰고 몇 초 기다린 뒤, 그래도 무시하는 프로세스에만 -9를 쓰세요.
macOS에는 BSD sed가 들어 있는데, 여기서는 -i에 백업 확장자 인수가 필요합니다. macOS에서는 sed -i '' 's/old/new/g' file이라고 써야 하지만, Linux GNU sed에서는 같은 명령이 ''를 스크립트로 읽어 실패합니다. 양쪽에서 모두 작동하는 형태는 sed -i.bak 's/old/new/g' file이며, 나중에 지울 수 있는 백업 사본이 남습니다.
거의 모두 같습니다. 핵심 도구는 어디서나 같은 GNU와 util-linux 프로젝트에서 나오기 때문입니다. 다른 것은 패키지 관리자(Debian과 Ubuntu는 apt, Fedora와 RHEL은 dnf, Arch는 pacman, openSUSE는 zypper이며 패키지 표에 나란히 표시), 일부 로그 파일 경로, 관리자 그룹(sudo와 wheel), 방화벽 프런트엔드(ufw와 firewalld)입니다. Alpine과 BusyBox 기반 시스템은 옵션이 더 적은 축소판 도구를 씁니다.
피해의 거의 전부는 몇 안 되는 명령어에서 나옵니다. 경로가 틀렸거나 비어 있는 rm -rf, 엉뚱한 디스크를 가리킨 dd나 mkfs, 시스템 디렉터리에 쓴 chmod -R 777이나 chown -R, 원본과 대상이 뒤바뀐 rsync --delete나 robocopy식 미러링, crontab -e 대신 친 crontab -r, -a 없이 쓴 usermod -G, 잘못된 위치에 -delete를 둔 find입니다. 시트에서 각각을 위험으로 표시하고 구체적으로 어떻게 잘못되는지 설명합니다.
대부분을 막아 주는 습관은 해가 없는 버전을 먼저 실행하는 것입니다. rm -rf 전에는 같은 경로로 ls를 실행하세요. find … -delete 전에는 같은 find를 -print로 실행하세요. rsync --delete 전에는 -n을 붙여 시험 실행하세요. dd나 mkfs 전에는 lsblk를 실행하고 장치 이름을 두 번 읽으세요. 스크립트에서는 $DIR 대신 ${DIR:?}를 쓰면, 변수가 비어 있을 때 경로가 /로 바뀌는 대신 스크립트가 중단됩니다.
셸 설정 두 가지도 도움이 됩니다. 스크립트 맨 위의 set -euo pipefail은 잘못된 상태로 계속 진행하는 대신 첫 오류에서 멈추게 하고, set -o noclobber는 >가 기존 파일을 덮어쓰지 않게 합니다.
macOS는 유닉스이지만 명령줄 도구는 GNU가 아니라 FreeBSD에서 왔기 때문에, Linux 튜토리얼에서 명령어를 복사할 때 바로 차이가 드러납니다.
• macOS의 sed -i는 인수가 필요합니다(sed -i '' …). -i.bak은 양쪽에서 작동합니다.
• macOS의 date에는 -d가 없습니다. 타임스탬프 변환은 date -r <epoch>, 상대 날짜는 date -v-2d를 쓰세요.
• stat은 GNU의 -c 대신 다른 서식 문자를 쓰는 -f를 사용합니다.
• macOS의 xargs는 입력이 비어 있으면 기본적으로 건너뛰지만, GNU xargs는 -r을 주지 않으면 명령을 한 번 실행합니다.
• du는 양쪽 모두 -d 1을 받지만 --max-depth는 GNU만 받습니다. macOS의 ps에는 --sort가 없습니다(ps aux -m이나 -r을 쓰세요).
• head -n -5, tac, free, ip, ss, timeout, watch는 기본 macOS에 없습니다.
Mac에서 GNU 동작이 필요하다면 Homebrew의 coreutils, gnu-sed, findutils 패키지가 g 접두사를 붙인 GNU 버전(gsed, gdate, gstat, gxargs)을 설치해 줍니다.
ls -l은 권한을 -rwxr-x---처럼 열 글자로 보여 줍니다. 첫 글자는 유형(- 파일, d 디렉터리, l 링크)이고, 나머지 아홉 글자는 소유자, 그룹, 기타 사용자에 대한 읽기·쓰기·실행 권한 세 묶음입니다. 숫자로는 r이 4, w가 2, x가 1이며 묶음별로 더하므로 rwxr-x---는 750입니다.
일반적인 모드: 보통 파일은 644, 디렉터리와 스크립트는 755, 개인 키와 비밀 정보가 담긴 파일은 600, ~/.ssh 같은 개인 디렉터리는 700입니다. 디렉터리에서 x는 ‘들어갈 수 있음’을 뜻하므로, 디렉터리에는 필요하고 일반 파일에는 필요 없습니다. 적용하기 전에 모드를 확인하고 싶다면 chmod 계산기로 기호 형식과 8진수 형식을 서로 변환할 수 있습니다.