Skip to content

Split View: Linux 커맨드라인 완전 정복: 개발자가 반드시 알아야 할 100가지 명령어와 실전 활용

✨ Learn with Quiz
|

Linux 커맨드라인 완전 정복: 개발자가 반드시 알아야 할 100가지 명령어와 실전 활용

1. 왜 Linux 커맨드라인인가?

개발자가 GUI 대신 터미널을 써야 하는 이유는 명확합니다. 속도, 자동화, 원격 서버 접근. 클라우드 서버의 90% 이상이 Linux를 사용하고, CI/CD 파이프라인은 모두 CLI 기반입니다. 커맨드라인을 모르면 서버에서 아무것도 할 수 없습니다.

이 글에서 다루는 내용

  • 파일 시스템 탐색과 조작 명령어 20가지
  • 텍스트 처리의 삼총사: grep, awk, sed 실전 예제
  • 프로세스와 서비스 관리
  • 네트워크 디버깅과 SSH 마스터하기
  • Bash 스크립팅 기초부터 실전까지
  • tmux와 Vim 필수 사용법
  • 시스템 모니터링과 트러블슈팅

2. 파일 시스템 탐색 (Navigation)

2.1 기본 탐색 명령어

# 현재 디렉토리 확인
pwd
# /home/developer/projects

# 디렉토리 이동
cd /var/log          # 절대 경로
cd ../config         # 상대 경로
cd ~                 # 홈 디렉토리
cd -                 # 이전 디렉토리

# 디렉토리 내용 확인
ls -la               # 숨김 파일 포함 상세 목록
ls -lhS              # 파일 크기 순 정렬 (사람이 읽기 쉬운 단위)
ls -lt               # 수정 시간 순 정렬
ls -R                # 재귀적 목록

2.2 파일 검색

# find: 디렉토리 트리에서 파일 검색
find /var/log -name "*.log" -mtime -7           # 7일 이내 수정된 .log 파일
find . -type f -size +100M                       # 100MB 이상 파일
find . -name "*.tmp" -exec rm -f {} \;           # .tmp 파일 찾아서 삭제
find . -type f -name "*.js" ! -path "*/node_modules/*"  # node_modules 제외

# locate: 색인 기반 빠른 검색
sudo updatedb        # 데이터베이스 업데이트
locate nginx.conf    # 빠른 파일 검색

# which / whereis: 실행 파일 위치
which python3        # /usr/bin/python3
whereis nginx        # 바이너리, 소스, 매뉴얼 위치

# tree: 디렉토리 구조 시각화
tree -L 2 -I "node_modules|.git"   # 2단계 깊이, 특정 디렉토리 제외

2.3 디렉토리 관리

# 디렉토리 생성
mkdir -p project/src/components     # 중간 디렉토리 자동 생성

# 디렉토리 스택 활용
pushd /etc/nginx     # 현재 위치 저장 후 이동
# ... 작업 수행 ...
popd                 # 저장된 위치로 복귀
dirs -v              # 스택 확인

3. 파일 조작 (File Manipulation)

3.1 복사, 이동, 삭제

# 복사
cp -r src/ backup/                  # 디렉토리 재귀 복사
cp -p important.conf important.conf.bak  # 권한/타임스탬프 보존

# 이동/이름 변경
mv old_name.txt new_name.txt        # 이름 변경
mv *.log /var/log/archive/          # 여러 파일 이동

# 삭제 (주의!)
rm -rf build/                       # 디렉토리 강제 삭제 (매우 주의)
rm -i *.tmp                         # 삭제 전 확인

# 안전한 대안
trash-put file.txt                  # 휴지통으로 이동 (trash-cli 패키지)

3.2 파일 권한과 소유권

# 권한 변경
chmod 755 script.sh                 # rwxr-xr-x
chmod +x deploy.sh                  # 실행 권한 추가
chmod -R 644 public/                # 재귀적 권한 변경

# 소유권 변경
chown www-data:www-data /var/www    # 소유자:그룹 변경
chown -R developer: project/        # 재귀적 소유자 변경

# 권한 숫자 이해
# r(4) + w(2) + x(1) = 7 (소유자)
# r(4) + x(1)        = 5 (그룹)
# r(4) + x(1)        = 5 (기타)
# 결과: 755

3.3 링크와 아카이브

# 심볼릭 링크 (바로가기)
ln -s /usr/local/bin/python3.11 /usr/local/bin/python
ls -la /usr/local/bin/python        # 링크 확인

# 하드 링크
ln original.txt hardlink.txt        # 같은 inode 공유

# 아카이브와 압축
tar -czf backup.tar.gz project/     # gzip 압축 아카이브 생성
tar -xzf backup.tar.gz              # 압축 해제
tar -xjf archive.tar.bz2            # bzip2 압축 해제

zip -r project.zip project/ -x "*/node_modules/*"  # node_modules 제외 zip
unzip project.zip -d /tmp/          # 특정 디렉토리에 해제

4. 텍스트 처리의 삼총사: grep, awk, sed

4.1 grep - 패턴 검색

# 기본 검색
grep "ERROR" /var/log/syslog              # ERROR 포함 줄 검색
grep -i "warning" app.log                  # 대소문자 무시
grep -r "TODO" src/ --include="*.py"       # Python 파일에서 재귀 검색
grep -n "function" script.js               # 줄 번호 표시

# 정규표현식
grep -E "^[0-9]{4}-[0-9]{2}" access.log   # 날짜 패턴으로 시작하는 줄
grep -P "\d+\.\d+\.\d+\.\d+" access.log   # IP 주소 패턴 (Perl 정규식)
grep -v "^#" config.ini                     # 주석 제외

# 실전: 로그에서 에러 컨텍스트 확인
grep -B 3 -A 5 "Exception" app.log         # 에러 전후 줄 포함

# 실전: 특정 HTTP 상태 코드 추출
grep -oP 'HTTP/\d\.\d" \K5\d{2}' access.log | sort | uniq -c | sort -rn

4.2 awk - 텍스트 처리 프로그래밍

# 필드 추출
awk '{print $1, $4}' access.log            # 1번째, 4번째 필드 출력
awk -F: '{print $1, $3}' /etc/passwd       # 구분자 지정

# 조건 필터링
awk '$9 >= 500' access.log                 # HTTP 5xx 에러만
awk '$3 > 1000 {print $1, $3}' data.txt    # 3번째 필드가 1000 초과

# 계산
awk '{sum += $5} END {print "Total:", sum}' sales.txt    # 합계
awk '{sum += $1; n++} END {print sum/n}' numbers.txt     # 평균

# 실전: 로그에서 IP별 요청 수 카운트
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

# 실전: CSV 처리
awk -F',' '{
  if ($3 > 100) {
    total += $3
    count++
  }
}
END {
  printf "Average: %.2f\n", total/count
}' sales.csv

# 실전: 특정 시간대 로그 필터링
awk '/2026-03-23 14:[0-5][0-9]/' application.log

4.3 sed - 스트림 편집기

# 문자열 치환
sed 's/old/new/g' file.txt                 # 모든 old를 new로
sed -i 's/localhost/0.0.0.0/g' config.yml  # 파일 직접 수정 (-i)
sed -i.bak 's/debug/info/g' app.conf      # 백업 생성 후 수정

# 줄 삭제
sed '/^$/d' file.txt                       # 빈 줄 삭제
sed '/^#/d' config.ini                     # 주석 줄 삭제
sed '1,5d' file.txt                        # 1-5번째 줄 삭제

# 줄 추가/삽입
sed '3a\New line after line 3' file.txt    # 3번째 줄 뒤에 추가
sed '1i\Header Line' file.txt              # 1번째 줄 앞에 삽입

# 실전: 설정 파일에서 특정 블록 추출
sed -n '/\[database\]/,/\[/p' config.ini

# 실전: 여러 치환을 한번에
sed -e 's/foo/bar/g' -e 's/baz/qux/g' -e '/^$/d' input.txt

4.4 기타 텍스트 도구

# cut: 필드 잘라내기
cut -d: -f1,3 /etc/passwd               # 구분자로 필드 추출
cut -c1-10 file.txt                      # 문자 위치로 추출

# sort와 uniq
sort -t: -k3 -n /etc/passwd             # 3번째 필드 숫자 정렬
sort -u file.txt                         # 정렬 + 중복 제거
uniq -c sorted.txt                       # 중복 횟수 카운트

# wc: 카운트
wc -l *.py                               # 파일별 줄 수
find . -name "*.java" | xargs wc -l | tail -1  # Java 전체 줄 수

# head / tail
head -20 file.txt                        # 처음 20줄
tail -f /var/log/syslog                  # 실시간 로그 모니터링
tail -f app.log | grep --line-buffered "ERROR"  # 실시간 에러 필터링

# diff: 파일 비교
diff -u old.conf new.conf               # 통합 diff 형식
diff -rq dir1/ dir2/                     # 디렉토리 비교 (다른 파일만)

# tr: 문자 변환
echo "Hello World" | tr 'A-Z' 'a-z'     # 소문자 변환
cat file.txt | tr -d '\r'               # Windows 줄바꿈 제거

# xargs: 파이프 결과를 인자로 전달
find . -name "*.log" | xargs gzip       # 찾은 파일 압축
cat urls.txt | xargs -P 4 -I {} curl -sO {}  # 4개 병렬 다운로드

5. 프로세스 관리

5.1 프로세스 확인

# ps: 프로세스 목록
ps aux                                   # 전체 프로세스
ps aux | grep nginx                      # 특정 프로세스 검색
ps -ef --forest                          # 프로세스 트리

# top / htop: 실시간 모니터링
top -o %MEM                              # 메모리 사용량 순
htop                                     # 대화형 모니터링 (더 직관적)

# pgrep / pidof: PID 찾기
pgrep -f "python app.py"                # 이름으로 PID 검색
pidof nginx                              # 프로세스 PID 확인

5.2 프로세스 제어

# kill: 프로세스 종료
kill -15 1234                            # SIGTERM (정상 종료 요청)
kill -9 1234                             # SIGKILL (강제 종료)
killall nginx                            # 이름으로 모든 프로세스 종료
pkill -f "node server"                   # 패턴 매칭으로 종료

# 백그라운드 실행
nohup python server.py > output.log 2>&1 &    # 로그아웃해도 유지
disown %1                                # 현재 쉘에서 분리

# jobs: 백그라운드 작업 관리
jobs -l                                  # 현재 쉘의 백그라운드 작업
fg %1                                    # 포그라운드로 전환
bg %1                                    # 백그라운드에서 계속 실행

5.3 systemd 서비스 관리

# 서비스 상태 확인/제어
sudo systemctl status nginx              # 상태 확인
sudo systemctl start nginx               # 시작
sudo systemctl stop nginx                # 중지
sudo systemctl restart nginx             # 재시작
sudo systemctl reload nginx              # 설정 리로드 (무중단)
sudo systemctl enable nginx              # 부팅 시 자동 시작

# 서비스 로그 확인
journalctl -u nginx -f                   # 실시간 로그
journalctl -u nginx --since "1 hour ago" # 최근 1시간 로그
journalctl -u nginx --no-pager -n 100   # 최근 100줄
journalctl -p err -b                     # 현재 부팅의 에러 로그만

# 서비스 파일 위치 확인
systemctl show nginx -p FragmentPath

6. 네트워크 명령어

6.1 HTTP 요청과 다운로드

# curl: HTTP 요청
curl -s https://api.example.com/data     # 기본 GET
curl -X POST -H "Content-Type: application/json" \
  -d '{"name":"test"}' https://api.example.com/users
curl -o file.zip https://example.com/file.zip  # 파일 다운로드
curl -I https://example.com               # 헤더만 확인
curl -w "@curl-format.txt" -o /dev/null -s https://example.com  # 응답 시간 측정

# wget: 파일 다운로드
wget -c https://example.com/large-file.iso     # 이어받기
wget -r -np -l 2 https://example.com/docs/     # 재귀 다운로드 (2단계)

6.2 네트워크 진단

# 연결 확인
ss -tlnp                                 # 열린 TCP 포트 확인
ss -tlnp | grep :8080                    # 특정 포트 사용 프로세스
netstat -tulpn                           # netstat 대안 (구버전)

# DNS 조회
dig example.com                          # DNS 조회
dig +short example.com A                 # 간단한 A 레코드 조회
dig @8.8.8.8 example.com                # 특정 DNS 서버로 조회
nslookup example.com                     # 간단한 DNS 조회

# 경로 추적
traceroute example.com                   # 네트워크 경로 추적
mtr example.com                          # 실시간 traceroute + ping

# 방화벽 (iptables / nftables)
sudo iptables -L -n -v                   # 현재 규칙 확인
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT   # HTTP 포트 허용
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT   # 특정 서브넷 허용

# 네트워크 인터페이스
ip addr show                             # IP 주소 확인
ip route show                            # 라우팅 테이블

7. SSH 마스터하기

7.1 SSH 기본과 설정

# SSH 키 생성
ssh-keygen -t ed25519 -C "dev@example.com"

# 공개키 복사
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# SSH 접속
ssh user@192.168.1.100
ssh -p 2222 user@server                  # 특정 포트

SSH 설정 파일로 접속을 편리하게 관리할 수 있습니다.

# ~/.ssh/config
Host production
    HostName 10.0.1.50
    User deploy
    Port 22
    IdentityFile ~/.ssh/prod_key
    ForwardAgent yes

Host staging
    HostName 10.0.2.50
    User deploy
    IdentityFile ~/.ssh/staging_key

Host bastion
    HostName bastion.example.com
    User admin
    IdentityFile ~/.ssh/bastion_key

Host internal-*
    ProxyJump bastion
    User developer

7.2 SSH 터널링

# 로컬 포트 포워딩: 원격 서비스에 로컬로 접근
# 로컬 5432 포트 -> 원격 서버의 DB(5432)에 연결
ssh -L 5432:db-server:5432 bastion-server

# 리버스 포트 포워딩: 로컬 서비스를 원격에서 접근
# 원격의 8080 -> 로컬의 3000
ssh -R 8080:localhost:3000 remote-server

# 동적 포트 포워딩 (SOCKS 프록시)
ssh -D 1080 proxy-server

# 실전: 여러 터널 한번에
ssh -L 5432:db:5432 -L 6379:redis:6379 -L 9200:elastic:9200 bastion

7.3 파일 전송

# scp: 간단한 파일 전송
scp local-file.txt user@server:/remote/path/
scp -r local-dir/ user@server:/remote/path/
scp user@server:/remote/file.txt ./local/

# rsync: 효율적인 동기화 (변경분만 전송)
rsync -avz --progress local/ user@server:/remote/
rsync -avz --delete local/ user@server:/remote/     # 원본에 없는 파일 삭제
rsync -avz --exclude "node_modules" --exclude ".git" \
  project/ user@server:/deploy/

8. Bash 스크립팅

8.1 기초 문법

#!/bin/bash
set -euo pipefail   # 에러 발생 시 즉시 중단, 미선언 변수 사용 방지

# 변수
APP_NAME="my-app"
VERSION="1.0.0"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# 문자열 조작
echo "App: $APP_NAME, Version: $VERSION"
echo "Length: ${#APP_NAME}"              # 문자열 길이
echo "${APP_NAME^^}"                      # 대문자 변환 (MY-APP)
echo "${APP_NAME/my/your}"               # 치환 (your-app)

8.2 조건문과 반복문

#!/bin/bash

# 조건문
if [ -f "/etc/nginx/nginx.conf" ]; then
    echo "Nginx config exists"
elif [ -f "/etc/apache2/apache2.conf" ]; then
    echo "Apache config exists"
else
    echo "No web server config found"
fi

# 파일 테스트 연산자
# -f: 파일 존재
# -d: 디렉토리 존재
# -r: 읽기 권한
# -w: 쓰기 권한
# -x: 실행 권한
# -s: 파일 크기가 0보다 큼

# for 루프
for server in web1 web2 web3; do
    echo "Deploying to $server..."
    ssh "$server" "cd /app && git pull && systemctl restart app"
done

# 파일 목록 순회
for file in /var/log/*.log; do
    echo "Processing: $file"
    gzip "$file"
done

# while 루프
while read -r line; do
    echo "Processing: $line"
done < input.txt

# 카운터 루프
count=0
while [ $count -lt 10 ]; do
    echo "Attempt $count"
    ((count++))
done

8.3 함수와 에러 처리

#!/bin/bash
set -euo pipefail

# 함수 정의
deploy() {
    local environment="$1"
    local version="$2"

    echo "Deploying version $version to $environment..."

    if ! docker pull "myapp:$version" 2>/dev/null; then
        echo "Error: Image myapp:$version not found"
        return 1
    fi

    docker stop myapp 2>/dev/null || true
    docker run -d --name myapp "myapp:$version"
    echo "Deploy complete!"
}

# 에러 핸들링
cleanup() {
    echo "Cleaning up temporary files..."
    rm -rf /tmp/deploy_*
}
trap cleanup EXIT    # 스크립트 종료 시 항상 실행

# getopts로 인자 파싱
usage() {
    echo "Usage: deploy.sh -e ENVIRONMENT -v VERSION [-d]"
    exit 1
}

DRY_RUN=false
while getopts "e:v:dh" opt; do
    case $opt in
        e) ENVIRONMENT="$OPTARG" ;;
        v) VERSION="$OPTARG" ;;
        d) DRY_RUN=true ;;
        h) usage ;;
        *) usage ;;
    esac
done

# 실행
deploy "$ENVIRONMENT" "$VERSION"

8.4 실전 스크립트: 자동 백업

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/backup"
DB_NAME="production"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_$TIMESTAMP.sql.gz"

# 로깅 함수
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 백업 실행
log "Starting backup of $DB_NAME..."
pg_dump "$DB_NAME" | gzip > "$BACKUP_FILE"

# 백업 검증
if [ -s "$BACKUP_FILE" ]; then
    SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    log "Backup successful: $BACKUP_FILE ($SIZE)"
else
    log "ERROR: Backup file is empty!"
    exit 1
fi

# 오래된 백업 정리
log "Removing backups older than $RETENTION_DAYS days..."
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" -mtime +$RETENTION_DAYS -delete

# 남은 백업 수 확인
REMAINING=$(find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" | wc -l)
log "Done. $REMAINING backups remaining."

9. tmux - 터미널 멀티플렉서

9.1 기본 사용법

# 세션 관리
tmux new -s dev                          # 새 세션 생성
tmux ls                                  # 세션 목록
tmux attach -t dev                       # 세션 연결
tmux kill-session -t dev                 # 세션 종료

9.2 주요 단축키

tmux의 기본 프리픽스 키는 Ctrl+b입니다.

동작단축키
수평 분할Ctrl+b %
수직 분할Ctrl+b "
패널 이동Ctrl+b 방향키
새 창Ctrl+b c
다음 창Ctrl+b n
이전 창Ctrl+b p
세션 분리Ctrl+b d
패널 크기 조절Ctrl+b Alt+방향키
패널 확대/축소Ctrl+b z

9.3 추천 tmux 설정

# ~/.tmux.conf
set -g mouse on                          # 마우스 지원
set -g history-limit 50000               # 스크롤백 버퍼 확대
set -g base-index 1                      # 창 번호 1부터 시작
setw -g pane-base-index 1               # 패널 번호 1부터 시작

# 프리픽스 키 변경 (Ctrl+a)
unbind C-b
set -g prefix C-a

# 직관적 분할 키
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Vi 모드
setw -g mode-keys vi

10. Vim 필수 사용법

10.1 모드와 기본 명령어

모드진입설명
NormalEsc명령어 실행
Inserti, a, o텍스트 입력
Visualv, V텍스트 선택
Command:Ex 명령어

10.2 생존 필수 명령어

# 이동
h/j/k/l                 왼/아래/위/오른
w / b                    단어 앞/뒤로
0 / $                    줄 시작/끝
gg / G                   파일 처음/끝
:42                      42번째 줄로 이동

# 편집
dd                       줄 삭제
yy                       줄 복사
p                        붙여넣기
u                        실행 취소
Ctrl+r                   다시 실행
.                        마지막 명령 반복

# 검색/치환
/pattern                 앞으로 검색
?pattern                 뒤로 검색
n / N                    다음/이전 결과
:%s/old/new/g            전체 치환
:%s/old/new/gc           확인하며 치환

# 저장/종료
:w                       저장
:q                       종료
:wq                      저장 후 종료
:q!                      저장 안 하고 종료

10.3 실전 Vim 팁

# 여러 파일 편집
:e filename              파일 열기
:bn / :bp                다음/이전 버퍼
:vs filename             수직 분할 열기

# 매크로
qa                       매크로 a 녹화 시작
q                        녹화 중지
@a                       매크로 a 실행
100@a                    100번 반복 실행

# 블록 편집 (여러 줄 주석 등)
Ctrl+v                   블록 선택
I                        블록 앞에 삽입
Esc                      적용

11. 시스템 모니터링

11.1 메모리와 디스크

# 메모리
free -h                                  # 메모리 사용량
cat /proc/meminfo                        # 상세 메모리 정보

# 디스크
df -h                                    # 디스크 사용량
du -sh /var/log/*                        # 디렉토리별 크기
du -h --max-depth=1 / | sort -rh | head -10  # 가장 큰 디렉토리

# 디스크 I/O
iostat -x 1                              # I/O 통계 (1초 간격)
iotop                                    # 프로세스별 I/O 사용량

11.2 CPU와 시스템 성능

# CPU 정보
lscpu                                    # CPU 정보
nproc                                    # CPU 코어 수
uptime                                   # 로드 평균

# vmstat: 가상 메모리 통계
vmstat 1 10                              # 1초 간격 10번

# sar: 시스템 활동 보고서
sar -u 1 5                               # CPU 사용률 (1초 간격 5번)
sar -r 1 5                               # 메모리 사용률
sar -n DEV 1 5                           # 네트워크 트래픽

# lsof: 열린 파일 목록
lsof -i :8080                            # 8080 포트 사용 프로세스
lsof -u developer                        # 특정 사용자의 열린 파일
lsof +D /var/log/                        # 특정 디렉토리의 열린 파일

# strace: 시스템 콜 추적 (디버깅용)
strace -f -e trace=network -p 1234       # 네트워크 관련 시스템 콜 추적

12. 패키지 관리

12.1 Debian/Ubuntu (apt)

sudo apt update                          # 패키지 목록 업데이트
sudo apt upgrade                         # 설치된 패키지 업그레이드
sudo apt install nginx                   # 패키지 설치
sudo apt remove nginx                    # 패키지 제거
sudo apt autoremove                      # 불필요한 패키지 정리
apt search keyword                       # 패키지 검색
apt show nginx                           # 패키지 정보
dpkg -l | grep nginx                     # 설치된 패키지 확인

12.2 RHEL/CentOS (yum/dnf)

sudo yum update                          # 업데이트
sudo yum install httpd                   # 설치
sudo yum remove httpd                    # 제거
yum search keyword                       # 검색
rpm -qa | grep httpd                     # 설치된 패키지 확인

12.3 macOS (brew)

brew update                              # Homebrew 업데이트
brew install jq                          # 패키지 설치
brew upgrade                             # 모든 패키지 업그레이드
brew list                                # 설치된 패키지 목록
brew cleanup                             # 캐시 정리

13. Docker CLI 필수 명령어

# 이미지 관리
docker images                            # 이미지 목록
docker pull nginx:latest                 # 이미지 다운로드
docker build -t myapp:1.0 .             # 이미지 빌드
docker rmi myapp:1.0                     # 이미지 삭제

# 컨테이너 관리
docker ps                                # 실행 중인 컨테이너
docker ps -a                             # 모든 컨테이너
docker run -d -p 8080:80 --name web nginx  # 백그라운드 실행
docker stop web                          # 컨테이너 중지
docker rm web                            # 컨테이너 삭제

# 디버깅
docker logs -f web                       # 실시간 로그
docker exec -it web /bin/bash            # 컨테이너 내부 접속
docker inspect web                       # 상세 정보

# 정리
docker system prune -a                   # 미사용 리소스 전체 정리
docker volume prune                      # 미사용 볼륨 정리

14. 파이프와 리다이렉트 심화

# 기본 리다이렉트
command > output.txt                     # 표준 출력을 파일로 (덮어쓰기)
command >> output.txt                    # 표준 출력을 파일로 (추가)
command 2> error.log                     # 표준 에러를 파일로
command > output.txt 2>&1                # 표준 출력 + 에러를 같은 파일로
command &> all.log                       # 위와 동일 (Bash 단축형)

# 파이프 체이닝 실전
# 가장 많은 메모리를 사용하는 프로세스 10개
ps aux --sort=-%mem | head -11

# 로그에서 에러 빈도 분석
cat app.log | grep "ERROR" | awk '{print $4}' | sort | uniq -c | sort -rn | head

# 실시간 로그에서 특정 패턴 알림
tail -f app.log | grep --line-buffered "CRITICAL" | while read line; do
    echo "ALERT: $line" | mail -s "Critical Error" admin@example.com
done

# 프로세스 치환
diff <(ssh server1 cat /etc/config) <(ssh server2 cat /etc/config)

# Here document
cat <<'SCRIPT' > /tmp/setup.sh
#!/bin/bash
echo "Running setup..."
apt update && apt install -y nginx
SCRIPT

15. 10가지 트러블슈팅 시나리오

시나리오 1: 디스크 공간 부족

# 1. 전체 디스크 사용량 확인
df -h

# 2. 큰 디렉토리 찾기
du -h --max-depth=1 / 2>/dev/null | sort -rh | head -10

# 3. 큰 파일 찾기
find / -type f -size +500M 2>/dev/null | head -20

# 4. 삭제되었지만 프로세스가 잡고 있는 파일 확인
lsof +L1

# 5. 로그 파일 정리
sudo journalctl --vacuum-size=500M
find /var/log -name "*.gz" -mtime +30 -delete

시나리오 2: 서비스가 응답하지 않음

# 1. 서비스 상태 확인
sudo systemctl status myapp

# 2. 포트 리스닝 확인
ss -tlnp | grep :8080

# 3. 프로세스 상태 확인
ps aux | grep myapp

# 4. 최근 로그 확인
journalctl -u myapp --since "10 minutes ago" --no-pager

# 5. 리소스 확인 (OOM Killer)
dmesg | grep -i "oom\|killed"

시나리오 3: 높은 CPU 사용률

# 1. CPU 소비 프로세스 확인
top -o %CPU -bn1 | head -15

# 2. 특정 프로세스의 스레드 확인
top -H -p $(pgrep myapp)

# 3. 시스템 콜 확인
strace -c -p $(pgrep myapp) -e trace=all

# 4. 로드 평균 히스토리
sar -u 1 10

시나리오 4: 네트워크 연결 문제

# 1. DNS 확인
dig api.example.com +short

# 2. 포트 연결 테스트
nc -zv api.example.com 443

# 3. 경로 추적
traceroute api.example.com

# 4. SSL 인증서 확인
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -text -noout | grep -A2 "Validity"

시나리오 5: 메모리 누수 조사

# 1. 메모리 사용량 추이 확인
watch -n 5 'free -h'

# 2. 프로세스별 메모리 사용량
ps aux --sort=-%mem | head -10

# 3. 특정 프로세스 메모리 상세
cat /proc/$(pgrep myapp)/status | grep -i "vm\|mem"

# 4. OOM Killer 로그
dmesg -T | grep -i "oom"

시나리오 6: 느린 디스크 I/O

# 1. I/O 대기 확인
iostat -x 1 5

# 2. I/O 많이 사용하는 프로세스
iotop -oP

# 3. 디스크 성능 테스트
dd if=/dev/zero of=testfile bs=1G count=1 oflag=direct

시나리오 7: SSH 접속 실패

# 1. 상세 디버그 모드로 접속 시도
ssh -vvv user@server

# 2. SSH 서비스 상태 확인 (서버에서)
sudo systemctl status sshd

# 3. 방화벽 확인
sudo iptables -L -n | grep 22

# 4. 인증 로그 확인
sudo tail -50 /var/log/auth.log

시나리오 8: 파일 권한 문제

# 1. 파일 권한 확인
ls -la /path/to/file
namei -l /path/to/file                   # 전체 경로의 권한 확인

# 2. SELinux / AppArmor 확인
getenforce                               # SELinux 상태
ls -Z /path/to/file                      # SELinux 컨텍스트

# 3. ACL 확인
getfacl /path/to/file

시나리오 9: 로그 분석으로 공격 탐지

# 1. 비정상 로그인 시도 확인
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head

# 2. 웹 서버 비정상 접근 확인
awk '$9 == 404' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head

# 3. 동시 접속 수 확인
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head

시나리오 10: 프로세스가 좀비 상태

# 1. 좀비 프로세스 확인
ps aux | awk '$8 ~ /Z/ {print}'

# 2. 부모 프로세스 찾기
ps -o ppid= -p ZOMBIE_PID

# 3. 부모 프로세스 재시작으로 정리
kill -SIGCHLD PARENT_PID
# 또는 부모 프로세스 재시작

16. 유용한 원라이너 모음

# 현재 디렉토리에서 가장 큰 파일 10개
find . -type f -exec du -h {} + | sort -rh | head -10

# 특정 포트를 사용하는 프로세스 즉시 종료
kill $(lsof -t -i:8080)

# Git 저장소에서 가장 큰 파일 찾기
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort -snk2 | tail -10

# 서버 응답 시간 측정 (10회 반복)
for i in $(seq 1 10); do curl -o /dev/null -s -w "%{time_total}\n" https://example.com; done

# JSON 파일 예쁘게 출력
cat data.json | python3 -m json.tool
# 또는
cat data.json | jq .

# 파일 인코딩 변환
iconv -f EUC-KR -t UTF-8 input.txt > output.txt

# 현재 쉘의 모든 환경변수를 정렬해서 보기
env | sort

# 특정 확장자 파일의 총 줄 수
find . -name "*.py" -exec wc -l {} + | tail -1

17. 면접 질문 15선

Q1. hard link와 symbolic link의 차이점은?

Hard link: 동일한 inode를 가리킵니다. 원본이 삭제되어도 접근 가능합니다. 파일 시스템을 넘어갈 수 없고, 디렉토리에 사용할 수 없습니다.

Symbolic link: 별도의 inode로 경로를 가리킵니다. 원본이 삭제되면 깨진 링크가 됩니다. 파일 시스템을 넘어 사용 가능하고, 디렉토리도 가능합니다.

# Hard link: 같은 inode 공유
ln original.txt hard.txt
ls -li original.txt hard.txt  # 같은 inode 번호

# Symbolic link: 다른 inode, 경로 참조
ln -s original.txt sym.txt
ls -li original.txt sym.txt  # 다른 inode 번호
Q2. 프로세스와 스레드의 차이점은?

프로세스: 독립적인 메모리 공간을 가지며, IPC(파이프, 소켓 등)로 통신합니다. 하나의 프로세스 충돌이 다른 프로세스에 영향을 주지 않습니다.

스레드: 같은 프로세스 내에서 메모리를 공유합니다. 컨텍스트 스위칭이 빠르지만, 하나의 스레드 오류가 전체 프로세스에 영향을 줄 수 있습니다.

# 프로세스 확인
ps -eLf | head   # 스레드(LWP) 포함 목록
# NLWP 열이 스레드 수를 나타냄

# 특정 프로세스의 스레드 수
ls /proc/PID/task/ | wc -l
Q3. 파일 권한 755와 644의 의미는?

755: rwxr-xr-x - 소유자(읽기/쓰기/실행), 그룹(읽기/실행), 기타(읽기/실행). 디렉토리와 실행 파일에 주로 사용합니다.

644: rw-r--r-- - 소유자(읽기/쓰기), 그룹(읽기), 기타(읽기). 일반 파일에 주로 사용합니다.

숫자 계산: r=4, w=2, x=1. 합산하여 각 위치(소유자/그룹/기타)를 표현합니다.

Q4. SIGTERM과 SIGKILL의 차이점은?

SIGTERM (15): 프로세스에 정상 종료를 요청합니다. 프로세스가 시그널 핸들러에서 정리 작업(파일 닫기, 임시 파일 삭제 등)을 수행한 후 종료할 수 있습니다. kill PID의 기본값입니다.

SIGKILL (9): 커널이 즉시 프로세스를 강제 종료합니다. 프로세스가 무시하거나 핸들링할 수 없습니다. 정리 작업 없이 즉시 종료되므로 데이터 손실 위험이 있습니다. 마지막 수단으로만 사용해야 합니다.

Q5. grep, awk, sed의 사용 시점은?
  • grep: 패턴 검색이 목적일 때 (특정 문자열이 포함된 줄 찾기)
  • awk: 필드 기반 데이터 처리가 필요할 때 (컬럼 추출, 계산, 조건 필터링)
  • sed: 스트림 편집이 필요할 때 (문자열 치환, 줄 삭제/추가)

실전에서는 이 세 도구를 파이프로 연결하여 사용하는 경우가 많습니다.

# 로그에서 5xx 에러를 일으킨 URL의 빈도 분석
grep " 5[0-9][0-9] " access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
Q6. 파이프(|)와 리다이렉트(>)의 차이점은?

파이프(|): 한 명령어의 표준 출력을 다른 명령어의 표준 입력으로 연결합니다. 프로세스 간 통신입니다.

리다이렉트(>): 명령어의 출력을 파일로 보냅니다. 프로세스와 파일 간 통신입니다.

# 파이프: ls 출력이 grep의 입력으로
ls -la | grep ".conf"

# 리다이렉트: ls 출력이 파일로
ls -la > filelist.txt
Q7. inode란 무엇인가?

inode는 파일 시스템에서 파일의 메타데이터를 저장하는 데이터 구조입니다. 파일 이름을 제외한 모든 정보(소유자, 권한, 크기, 타임스탬프, 데이터 블록 위치)를 포함합니다. 디렉토리 엔트리가 파일 이름과 inode 번호를 매핑합니다.

# inode 번호 확인
ls -i file.txt
stat file.txt           # 상세 inode 정보

# inode 사용량 확인 (파일 수 제한)
df -i
Q8. SSH 터널링 3종류를 설명하세요.
  1. 로컬 포트 포워딩 (-L): 로컬 포트를 통해 원격 서비스에 접근. ssh -L 5432:db:5432 bastion - 로컬의 5432로 접속하면 bastion을 거쳐 db의 5432에 연결.

  2. 리모트 포트 포워딩 (-R): 원격에서 로컬 서비스에 접근. ssh -R 8080:localhost:3000 server - server의 8080으로 접속하면 로컬의 3000에 연결.

  3. 동적 포트 포워딩 (-D): SOCKS 프록시 생성. ssh -D 1080 server - 로컬 1080을 SOCKS 프록시로 사용하여 server를 통해 모든 트래픽 전달.

Q9. 좀비 프로세스란 무엇이며 어떻게 처리하나요?

좀비 프로세스는 실행이 끝났지만 부모 프로세스가 wait() 시스템 콜로 종료 상태를 아직 수거하지 않은 프로세스입니다. PID만 차지하고 리소스는 사용하지 않지만, 많이 쌓이면 PID 고갈 문제가 발생합니다.

처리 방법: 부모 프로세스에 SIGCHLD를 보내거나, 부모 프로세스를 종료하면 init/systemd가 고아 프로세스를 인수하여 정리합니다.

ps aux | awk '$8=="Z"'           # 좀비 프로세스 확인
kill -SIGCHLD PARENT_PID         # 부모에게 자식 종료 알림
Q10. /proc 파일 시스템이란?

/proc는 커널과 프로세스 정보를 파일 형태로 제공하는 가상 파일 시스템입니다. 디스크에 실제로 존재하지 않으며, 커널이 실시간으로 생성합니다.

cat /proc/cpuinfo        # CPU 정보
cat /proc/meminfo        # 메모리 정보
cat /proc/PID/status     # 특정 프로세스 상태
cat /proc/PID/fd/        # 열린 파일 디스크립터
cat /proc/loadavg        # 시스템 부하
Q11. stdin, stdout, stderr의 파일 디스크립터 번호는?
  • 0: stdin (표준 입력)
  • 1: stdout (표준 출력)
  • 2: stderr (표준 에러)
command > file.txt       # 1번(stdout)을 파일로
command 2> error.log     # 2번(stderr)을 파일로
command > file.txt 2>&1  # stderr를 stdout과 같은 곳으로
command < input.txt      # 0번(stdin)을 파일에서 읽기
Q12. cron과 at의 차이점은?

cron: 반복적인 스케줄 작업에 사용합니다. crontab 파일로 관리합니다.

# 분 시 일 월 요일 명령어
crontab -e
0 2 * * * /backup/run.sh    # 매일 새벽 2시
*/5 * * * * /check/health.sh # 5분마다

at: 일회성 작업에 사용합니다.

at now + 30 minutes
> /scripts/deploy.sh
> Ctrl+D
Q13. 로드 평균(Load Average)이란?

로드 평균은 실행 가능(Running) 또는 대기(Waiting) 상태인 프로세스의 평균 수입니다. uptime 명령어로 1분, 5분, 15분 평균을 확인합니다.

해석: CPU 코어 수와 비교합니다. 4코어 시스템에서 로드 평균 4.0이면 100% 활용, 8.0이면 과부하(프로세스가 대기 중)입니다.

uptime                   # load average: 2.50, 3.10, 2.80
nproc                    # CPU 코어 수 확인
Q14. swap 메모리란? 왜 서버에서는 주의해야 하나요?

Swap은 RAM이 부족할 때 디스크를 메모리처럼 사용하는 공간입니다. 디스크 I/O는 RAM보다 수천 배 느리므로, 서버가 swap을 활발히 사용하면 성능이 급격히 저하됩니다.

free -h                  # swap 사용량 확인
swapon --show            # swap 디바이스 확인
vmstat 1                 # si/so 값이 크면 swap 활발히 사용 중
cat /proc/sys/vm/swappiness  # swap 사용 경향 (0-100, 낮을수록 RAM 우선)
Q15. set -euo pipefail은 무엇을 하나요?

Bash 스크립트의 안전 장치입니다.

  • -e (errexit): 명령어가 실패(non-zero exit)하면 스크립트 즉시 중단
  • -u (nounset): 선언되지 않은 변수 사용 시 에러 발생
  • -o pipefail: 파이프라인에서 중간 명령어 실패도 감지

이 세 옵션 없이는 에러가 무시되어 예상치 못한 동작이 발생할 수 있습니다. 프로덕션 스크립트에서는 항상 사용하는 것이 권장됩니다.


18. 퀴즈

Q1. 다음 명령어의 출력 결과는? echo "Hello" | tee output.txt | wc -c

답: 6

tee는 stdin을 output.txt에 쓰면서 동시에 stdout으로 전달합니다. wc -c는 바이트 수를 세는데, "Hello\n" = 6바이트입니다.

Q2. chmod 4755 script.sh에서 4는 무엇을 의미하나요?

답: SetUID 비트

4는 SetUID(Set User ID) 비트입니다. 이 파일을 실행하면 파일 소유자의 권한으로 실행됩니다. 예를 들어 /usr/bin/passwd가 root 소유이면서 SetUID가 설정되어 있어 일반 사용자도 비밀번호를 변경할 수 있습니다. SetGID는 2, Sticky Bit는 1입니다.

Q3. 다음 중 파일을 실시간으로 모니터링하면서 특정 패턴만 필터링하는 올바른 방법은?

A) grep "ERROR" < tail -f app.log B) tail -f app.log | grep "ERROR" C) tail -f app.log > grep "ERROR" D) cat app.log | tail -f | grep "ERROR"

답: B

tail -f의 출력을 파이프로 grep에 전달합니다. A는 문법 오류, C는 리다이렉트가 잘못 사용됨, D는 cat이 먼저 전체를 읽어 tail -f가 의미 없습니다.

Q4. ssh -L 3306:db-server:3306 bastion에서 실제로 일어나는 일은?

: 로컬 머신의 3306 포트로 접속하면, SSH 연결을 통해 bastion 서버를 경유하여 db-server의 3306 포트(MySQL)에 연결됩니다. 로컬에서 mysql -h 127.0.0.1 -P 3306으로 원격 DB에 접속할 수 있습니다. 통신은 SSH로 암호화됩니다.

Q5. 다음 스크립트에서 버그를 찾으세요.
#!/bin/bash
for f in $(ls *.txt); do
    mv "$f" "${f%.txt}.md"
done

: ls 출력을 for 루프에 사용하면 파일 이름에 공백이 있을 때 깨집니다. 올바른 방법:

#!/bin/bash
for f in *.txt; do
    [ -e "$f" ] || continue
    mv "$f" "${f%.txt}.md"
done

glob 패턴을 직접 사용하고, 매칭 파일이 없을 때를 대비해 존재 확인을 합니다.


19. 참고 자료

공식 문서 및 매뉴얼

  1. GNU Coreutils Manual - 핵심 유틸리티 공식 문서
  2. GNU Bash Manual - Bash 공식 레퍼런스
  3. The Linux Documentation Project - Linux 종합 문서 프로젝트
  4. man7.org Linux Manual Pages - Linux man page 온라인 버전
  5. tmux Wiki - tmux 공식 위키

학습 리소스

  1. Linux Journey - 초보자 친화적 Linux 학습 사이트
  2. OverTheWire Bandit - 게임으로 배우는 Linux 명령어
  3. Vim Adventures - 게임으로 배우는 Vim
  4. ExplainShell - 명령어를 입력하면 각 부분을 설명해주는 도구
  5. ShellCheck - Bash 스크립트 린터/분석기

도서

  1. The Linux Command Line (William Shotts) - Linux CLI 바이블
  2. Linux Pocket Guide (Daniel J. Barrett) - 빠른 참조용
  3. Bash Cookbook (Carl Albing) - Bash 레시피 모음
  4. sed and awk (Dale Dougherty) - 텍스트 처리 심화

치트시트

  1. devhints.io/bash - Bash 치트시트
  2. tmux Cheat Sheet - tmux 단축키 모음
  3. Vim Cheat Sheet - Vim 명령어 모음

Mastering Linux Command Line: 100 Essential Commands Every Developer Must Know

1. Why the Linux Command Line?

The reasons developers should use the terminal over GUIs are clear: speed, automation, and remote server access. Over 90% of cloud servers run Linux, and CI/CD pipelines are entirely CLI-based. Without command line skills, you cannot do anything on a server.

What This Guide Covers

  • 20 file system navigation and manipulation commands
  • The holy trinity of text processing: grep, awk, sed with real examples
  • Process and service management
  • Network debugging and mastering SSH
  • Bash scripting from basics to production
  • tmux and Vim essentials
  • System monitoring and troubleshooting

2. File System Navigation

2.1 Basic Navigation Commands

# Check current directory
pwd
# /home/developer/projects

# Change directory
cd /var/log          # Absolute path
cd ../config         # Relative path
cd ~                 # Home directory
cd -                 # Previous directory

# List directory contents
ls -la               # Detailed list including hidden files
ls -lhS              # Sort by size (human-readable)
ls -lt               # Sort by modification time
ls -R                # Recursive listing
# find: Search for files in directory tree
find /var/log -name "*.log" -mtime -7           # .log files modified within 7 days
find . -type f -size +100M                       # Files larger than 100MB
find . -name "*.tmp" -exec rm -f {} \;           # Find and delete .tmp files
find . -type f -name "*.js" ! -path "*/node_modules/*"  # Exclude node_modules

# locate: Fast index-based search
sudo updatedb        # Update database
locate nginx.conf    # Quick file search

# which / whereis: Find executables
which python3        # /usr/bin/python3
whereis nginx        # Binary, source, manual locations

# tree: Visualize directory structure
tree -L 2 -I "node_modules|.git"   # 2 levels deep, exclude specific directories

2.3 Directory Management

# Create directories
mkdir -p project/src/components     # Create intermediate directories

# Directory stack
pushd /etc/nginx     # Save current location and navigate
# ... do work ...
popd                 # Return to saved location
dirs -v              # View stack

3. File Manipulation

3.1 Copy, Move, Delete

# Copy
cp -r src/ backup/                  # Recursive directory copy
cp -p important.conf important.conf.bak  # Preserve permissions/timestamps

# Move/Rename
mv old_name.txt new_name.txt        # Rename
mv *.log /var/log/archive/          # Move multiple files

# Delete (careful!)
rm -rf build/                       # Force delete directory (use with caution)
rm -i *.tmp                         # Confirm before deleting

# Safer alternative
trash-put file.txt                  # Move to trash (trash-cli package)

3.2 File Permissions and Ownership

# Change permissions
chmod 755 script.sh                 # rwxr-xr-x
chmod +x deploy.sh                  # Add execute permission
chmod -R 644 public/                # Recursive permission change

# Change ownership
chown www-data:www-data /var/www    # Change owner:group
chown -R developer: project/        # Recursive ownership change

# Understanding permission numbers
# r(4) + w(2) + x(1) = 7 (owner)
# r(4) + x(1)        = 5 (group)
# r(4) + x(1)        = 5 (others)
# Result: 755
# Symbolic link (shortcut)
ln -s /usr/local/bin/python3.11 /usr/local/bin/python
ls -la /usr/local/bin/python        # Verify link

# Hard link
ln original.txt hardlink.txt        # Shares the same inode

# Archives and compression
tar -czf backup.tar.gz project/     # Create gzip compressed archive
tar -xzf backup.tar.gz              # Extract
tar -xjf archive.tar.bz2            # Extract bzip2 archive

zip -r project.zip project/ -x "*/node_modules/*"  # Zip excluding node_modules
unzip project.zip -d /tmp/          # Extract to specific directory

4. The Holy Trinity of Text Processing: grep, awk, sed

# Basic search
grep "ERROR" /var/log/syslog              # Search lines containing ERROR
grep -i "warning" app.log                  # Case-insensitive
grep -r "TODO" src/ --include="*.py"       # Recursive search in Python files
grep -n "function" script.js               # Show line numbers

# Regular expressions
grep -E "^[0-9]{4}-[0-9]{2}" access.log   # Lines starting with date pattern
grep -P "\d+\.\d+\.\d+\.\d+" access.log   # IP address pattern (Perl regex)
grep -v "^#" config.ini                     # Exclude comments

# Practical: Check error context in logs
grep -B 3 -A 5 "Exception" app.log         # Include surrounding lines

# Practical: Extract HTTP status codes
grep -oP 'HTTP/\d\.\d" \K5\d{2}' access.log | sort | uniq -c | sort -rn

4.2 awk - Text Processing Programming

# Field extraction
awk '{print $1, $4}' access.log            # Print 1st and 4th fields
awk -F: '{print $1, $3}' /etc/passwd       # Specify delimiter

# Conditional filtering
awk '$9 >= 500' access.log                 # HTTP 5xx errors only
awk '$3 > 1000 {print $1, $3}' data.txt    # 3rd field greater than 1000

# Calculations
awk '{sum += $5} END {print "Total:", sum}' sales.txt    # Sum
awk '{sum += $1; n++} END {print sum/n}' numbers.txt     # Average

# Practical: Count requests per IP from logs
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

# Practical: CSV processing
awk -F',' '{
  if ($3 > 100) {
    total += $3
    count++
  }
}
END {
  printf "Average: %.2f\n", total/count
}' sales.csv

# Practical: Filter logs by time range
awk '/2026-03-23 14:[0-5][0-9]/' application.log

4.3 sed - Stream Editor

# String substitution
sed 's/old/new/g' file.txt                 # Replace all old with new
sed -i 's/localhost/0.0.0.0/g' config.yml  # Edit file in place (-i)
sed -i.bak 's/debug/info/g' app.conf      # Create backup before editing

# Delete lines
sed '/^$/d' file.txt                       # Delete empty lines
sed '/^#/d' config.ini                     # Delete comment lines
sed '1,5d' file.txt                        # Delete lines 1-5

# Add/insert lines
sed '3a\New line after line 3' file.txt    # Add after line 3
sed '1i\Header Line' file.txt              # Insert before line 1

# Practical: Extract specific block from config file
sed -n '/\[database\]/,/\[/p' config.ini

# Practical: Multiple substitutions at once
sed -e 's/foo/bar/g' -e 's/baz/qux/g' -e '/^$/d' input.txt

4.4 Other Text Tools

# cut: Extract fields
cut -d: -f1,3 /etc/passwd               # Extract fields by delimiter
cut -c1-10 file.txt                      # Extract by character position

# sort and uniq
sort -t: -k3 -n /etc/passwd             # Sort by 3rd field numerically
sort -u file.txt                         # Sort + remove duplicates
uniq -c sorted.txt                       # Count duplicates

# wc: Count
wc -l *.py                               # Line count per file
find . -name "*.java" | xargs wc -l | tail -1  # Total Java line count

# head / tail
head -20 file.txt                        # First 20 lines
tail -f /var/log/syslog                  # Real-time log monitoring
tail -f app.log | grep --line-buffered "ERROR"  # Real-time error filtering

# diff: Compare files
diff -u old.conf new.conf               # Unified diff format
diff -rq dir1/ dir2/                     # Compare directories (different files only)

# tr: Character translation
echo "Hello World" | tr 'A-Z' 'a-z'     # Convert to lowercase
cat file.txt | tr -d '\r'               # Remove Windows line endings

# xargs: Pass pipe results as arguments
find . -name "*.log" | xargs gzip       # Compress found files
cat urls.txt | xargs -P 4 -I {} curl -sO {}  # 4 parallel downloads

5. Process Management

5.1 Viewing Processes

# ps: Process list
ps aux                                   # All processes
ps aux | grep nginx                      # Search specific process
ps -ef --forest                          # Process tree

# top / htop: Real-time monitoring
top -o %MEM                              # Sort by memory usage
htop                                     # Interactive monitoring (more intuitive)

# pgrep / pidof: Find PIDs
pgrep -f "python app.py"                # Search PID by name
pidof nginx                              # Get process PID

5.2 Process Control

# kill: Terminate processes
kill -15 1234                            # SIGTERM (graceful shutdown request)
kill -9 1234                             # SIGKILL (force kill)
killall nginx                            # Kill all by name
pkill -f "node server"                   # Kill by pattern match

# Background execution
nohup python server.py > output.log 2>&1 &    # Survives logout
disown %1                                # Detach from current shell

# jobs: Background job management
jobs -l                                  # Current shell background jobs
fg %1                                    # Bring to foreground
bg %1                                    # Continue in background

5.3 systemd Service Management

# Service status/control
sudo systemctl status nginx              # Check status
sudo systemctl start nginx               # Start
sudo systemctl stop nginx                # Stop
sudo systemctl restart nginx             # Restart
sudo systemctl reload nginx              # Reload config (no downtime)
sudo systemctl enable nginx              # Auto-start on boot

# Service logs
journalctl -u nginx -f                   # Real-time logs
journalctl -u nginx --since "1 hour ago" # Last hour logs
journalctl -u nginx --no-pager -n 100   # Last 100 lines
journalctl -p err -b                     # Error logs from current boot only

# Service file location
systemctl show nginx -p FragmentPath

6. Network Commands

6.1 HTTP Requests and Downloads

# curl: HTTP requests
curl -s https://api.example.com/data     # Basic GET
curl -X POST -H "Content-Type: application/json" \
  -d '{"name":"test"}' https://api.example.com/users
curl -o file.zip https://example.com/file.zip  # Download file
curl -I https://example.com               # Headers only
curl -w "@curl-format.txt" -o /dev/null -s https://example.com  # Measure response time

# wget: File downloads
wget -c https://example.com/large-file.iso     # Resume download
wget -r -np -l 2 https://example.com/docs/     # Recursive download (2 levels)

6.2 Network Diagnostics

# Connection check
ss -tlnp                                 # Check open TCP ports
ss -tlnp | grep :8080                    # Find process using specific port
netstat -tulpn                           # netstat alternative (legacy)

# DNS lookup
dig example.com                          # DNS query
dig +short example.com A                 # Simple A record query
dig @8.8.8.8 example.com                # Query specific DNS server
nslookup example.com                     # Simple DNS lookup

# Route tracing
traceroute example.com                   # Network path tracing
mtr example.com                          # Real-time traceroute + ping

# Firewall (iptables / nftables)
sudo iptables -L -n -v                   # View current rules
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT   # Allow HTTP port
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT   # Allow specific subnet

# Network interfaces
ip addr show                             # Show IP addresses
ip route show                            # Routing table

7. Mastering SSH

7.1 SSH Basics and Configuration

# Generate SSH key
ssh-keygen -t ed25519 -C "dev@example.com"

# Copy public key
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# SSH connection
ssh user@192.168.1.100
ssh -p 2222 user@server                  # Specific port

SSH config file makes connection management convenient.

# ~/.ssh/config
Host production
    HostName 10.0.1.50
    User deploy
    Port 22
    IdentityFile ~/.ssh/prod_key
    ForwardAgent yes

Host staging
    HostName 10.0.2.50
    User deploy
    IdentityFile ~/.ssh/staging_key

Host bastion
    HostName bastion.example.com
    User admin
    IdentityFile ~/.ssh/bastion_key

Host internal-*
    ProxyJump bastion
    User developer

7.2 SSH Tunneling

# Local port forwarding: Access remote service locally
# Local port 5432 -> Remote server DB(5432)
ssh -L 5432:db-server:5432 bastion-server

# Reverse port forwarding: Access local service from remote
# Remote 8080 -> Local 3000
ssh -R 8080:localhost:3000 remote-server

# Dynamic port forwarding (SOCKS proxy)
ssh -D 1080 proxy-server

# Practical: Multiple tunnels at once
ssh -L 5432:db:5432 -L 6379:redis:6379 -L 9200:elastic:9200 bastion

7.3 File Transfer

# scp: Simple file transfer
scp local-file.txt user@server:/remote/path/
scp -r local-dir/ user@server:/remote/path/
scp user@server:/remote/file.txt ./local/

# rsync: Efficient synchronization (transfers only changes)
rsync -avz --progress local/ user@server:/remote/
rsync -avz --delete local/ user@server:/remote/     # Delete files not in source
rsync -avz --exclude "node_modules" --exclude ".git" \
  project/ user@server:/deploy/

8. Bash Scripting

8.1 Basic Syntax

#!/bin/bash
set -euo pipefail   # Exit on error, undefined variables, pipe failures

# Variables
APP_NAME="my-app"
VERSION="1.0.0"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# String manipulation
echo "App: $APP_NAME, Version: $VERSION"
echo "Length: ${#APP_NAME}"              # String length
echo "${APP_NAME^^}"                      # Uppercase (MY-APP)
echo "${APP_NAME/my/your}"               # Substitution (your-app)

8.2 Conditionals and Loops

#!/bin/bash

# Conditionals
if [ -f "/etc/nginx/nginx.conf" ]; then
    echo "Nginx config exists"
elif [ -f "/etc/apache2/apache2.conf" ]; then
    echo "Apache config exists"
else
    echo "No web server config found"
fi

# File test operators
# -f: File exists
# -d: Directory exists
# -r: Read permission
# -w: Write permission
# -x: Execute permission
# -s: File size greater than 0

# for loop
for server in web1 web2 web3; do
    echo "Deploying to $server..."
    ssh "$server" "cd /app && git pull && systemctl restart app"
done

# Iterate over files
for file in /var/log/*.log; do
    echo "Processing: $file"
    gzip "$file"
done

# while loop
while read -r line; do
    echo "Processing: $line"
done < input.txt

# Counter loop
count=0
while [ $count -lt 10 ]; do
    echo "Attempt $count"
    ((count++))
done

8.3 Functions and Error Handling

#!/bin/bash
set -euo pipefail

# Function definition
deploy() {
    local environment="$1"
    local version="$2"

    echo "Deploying version $version to $environment..."

    if ! docker pull "myapp:$version" 2>/dev/null; then
        echo "Error: Image myapp:$version not found"
        return 1
    fi

    docker stop myapp 2>/dev/null || true
    docker run -d --name myapp "myapp:$version"
    echo "Deploy complete!"
}

# Error handling
cleanup() {
    echo "Cleaning up temporary files..."
    rm -rf /tmp/deploy_*
}
trap cleanup EXIT    # Always runs on script exit

# Argument parsing with getopts
usage() {
    echo "Usage: deploy.sh -e ENVIRONMENT -v VERSION [-d]"
    exit 1
}

DRY_RUN=false
while getopts "e:v:dh" opt; do
    case $opt in
        e) ENVIRONMENT="$OPTARG" ;;
        v) VERSION="$OPTARG" ;;
        d) DRY_RUN=true ;;
        h) usage ;;
        *) usage ;;
    esac
done

# Execute
deploy "$ENVIRONMENT" "$VERSION"

8.4 Practical Script: Automated Backup

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/backup"
DB_NAME="production"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_$TIMESTAMP.sql.gz"

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# Execute backup
log "Starting backup of $DB_NAME..."
pg_dump "$DB_NAME" | gzip > "$BACKUP_FILE"

# Verify backup
if [ -s "$BACKUP_FILE" ]; then
    SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
    log "Backup successful: $BACKUP_FILE ($SIZE)"
else
    log "ERROR: Backup file is empty!"
    exit 1
fi

# Clean old backups
log "Removing backups older than $RETENTION_DAYS days..."
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" -mtime +$RETENTION_DAYS -delete

# Check remaining backups
REMAINING=$(find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" | wc -l)
log "Done. $REMAINING backups remaining."

9. tmux - Terminal Multiplexer

9.1 Basic Usage

# Session management
tmux new -s dev                          # Create new session
tmux ls                                  # List sessions
tmux attach -t dev                       # Attach to session
tmux kill-session -t dev                 # Kill session

9.2 Key Shortcuts

The default tmux prefix key is Ctrl+b.

ActionShortcut
Horizontal splitCtrl+b %
Vertical splitCtrl+b "
Navigate panesCtrl+b Arrow keys
New windowCtrl+b c
Next windowCtrl+b n
Previous windowCtrl+b p
Detach sessionCtrl+b d
Resize paneCtrl+b Alt+Arrow keys
Zoom paneCtrl+b z
# ~/.tmux.conf
set -g mouse on                          # Mouse support
set -g history-limit 50000               # Increase scrollback buffer
set -g base-index 1                      # Window numbering from 1
setw -g pane-base-index 1               # Pane numbering from 1

# Change prefix key (Ctrl+a)
unbind C-b
set -g prefix C-a

# Intuitive split keys
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Vi mode
setw -g mode-keys vi

10. Vim Essentials

10.1 Modes and Basic Commands

ModeEnterDescription
NormalEscExecute commands
Inserti, a, oEnter text
Visualv, VSelect text
Command:Ex commands

10.2 Survival Commands

# Navigation
h/j/k/l                 left/down/up/right
w / b                    word forward/backward
0 / $                    line start/end
gg / G                   file start/end
:42                      go to line 42

# Editing
dd                       delete line
yy                       yank (copy) line
p                        paste
u                        undo
Ctrl+r                   redo
.                        repeat last command

# Search/Replace
/pattern                 search forward
?pattern                 search backward
n / N                    next/previous result
:%s/old/new/g            replace all
:%s/old/new/gc           replace with confirmation

# Save/Quit
:w                       save
:q                       quit
:wq                      save and quit
:q!                      quit without saving

10.3 Practical Vim Tips

# Edit multiple files
:e filename              open file
:bn / :bp                next/previous buffer
:vs filename             vertical split open

# Macros
qa                       start recording macro a
q                        stop recording
@a                       execute macro a
100@a                    execute 100 times

# Block editing (multi-line comments etc.)
Ctrl+v                   block select
I                        insert before block
Esc                      apply

11. System Monitoring

11.1 Memory and Disk

# Memory
free -h                                  # Memory usage
cat /proc/meminfo                        # Detailed memory info

# Disk
df -h                                    # Disk usage
du -sh /var/log/*                        # Size per directory
du -h --max-depth=1 / | sort -rh | head -10  # Largest directories

# Disk I/O
iostat -x 1                              # I/O statistics (1 second interval)
iotop                                    # Per-process I/O usage

11.2 CPU and System Performance

# CPU info
lscpu                                    # CPU information
nproc                                    # Number of CPU cores
uptime                                   # Load average

# vmstat: Virtual memory statistics
vmstat 1 10                              # 1 second interval, 10 times

# sar: System activity reporter
sar -u 1 5                               # CPU usage (1 sec, 5 times)
sar -r 1 5                               # Memory usage
sar -n DEV 1 5                           # Network traffic

# lsof: List open files
lsof -i :8080                            # Process using port 8080
lsof -u developer                        # Open files by user
lsof +D /var/log/                        # Open files in directory

# strace: Trace system calls (debugging)
strace -f -e trace=network -p 1234       # Trace network-related system calls

12. Package Management

12.1 Debian/Ubuntu (apt)

sudo apt update                          # Update package list
sudo apt upgrade                         # Upgrade installed packages
sudo apt install nginx                   # Install package
sudo apt remove nginx                    # Remove package
sudo apt autoremove                      # Clean unnecessary packages
apt search keyword                       # Search packages
apt show nginx                           # Package info
dpkg -l | grep nginx                     # Check installed packages

12.2 RHEL/CentOS (yum/dnf)

sudo yum update                          # Update
sudo yum install httpd                   # Install
sudo yum remove httpd                    # Remove
yum search keyword                       # Search
rpm -qa | grep httpd                     # Check installed packages

12.3 macOS (brew)

brew update                              # Update Homebrew
brew install jq                          # Install package
brew upgrade                             # Upgrade all packages
brew list                                # List installed packages
brew cleanup                             # Clean cache

13. Docker CLI Essentials

# Image management
docker images                            # List images
docker pull nginx:latest                 # Pull image
docker build -t myapp:1.0 .             # Build image
docker rmi myapp:1.0                     # Remove image

# Container management
docker ps                                # Running containers
docker ps -a                             # All containers
docker run -d -p 8080:80 --name web nginx  # Run in background
docker stop web                          # Stop container
docker rm web                            # Remove container

# Debugging
docker logs -f web                       # Real-time logs
docker exec -it web /bin/bash            # Enter container shell
docker inspect web                       # Detailed information

# Cleanup
docker system prune -a                   # Remove all unused resources
docker volume prune                      # Remove unused volumes

14. Advanced Pipes and Redirects

# Basic redirects
command > output.txt                     # stdout to file (overwrite)
command >> output.txt                    # stdout to file (append)
command 2> error.log                     # stderr to file
command > output.txt 2>&1                # stdout + stderr to same file
command &> all.log                       # Same as above (Bash shorthand)

# Pipe chaining in practice
# Top 10 memory-consuming processes
ps aux --sort=-%mem | head -11

# Error frequency analysis from logs
cat app.log | grep "ERROR" | awk '{print $4}' | sort | uniq -c | sort -rn | head

# Real-time alert for specific pattern in logs
tail -f app.log | grep --line-buffered "CRITICAL" | while read line; do
    echo "ALERT: $line" | mail -s "Critical Error" admin@example.com
done

# Process substitution
diff <(ssh server1 cat /etc/config) <(ssh server2 cat /etc/config)

# Here document
cat <<'SCRIPT' > /tmp/setup.sh
#!/bin/bash
echo "Running setup..."
apt update && apt install -y nginx
SCRIPT

15. 10 Troubleshooting Scenarios

Scenario 1: Disk Space Full

# 1. Check overall disk usage
df -h

# 2. Find large directories
du -h --max-depth=1 / 2>/dev/null | sort -rh | head -10

# 3. Find large files
find / -type f -size +500M 2>/dev/null | head -20

# 4. Check deleted files still held by processes
lsof +L1

# 5. Clean log files
sudo journalctl --vacuum-size=500M
find /var/log -name "*.gz" -mtime +30 -delete

Scenario 2: Service Not Responding

# 1. Check service status
sudo systemctl status myapp

# 2. Verify port listening
ss -tlnp | grep :8080

# 3. Check process status
ps aux | grep myapp

# 4. Check recent logs
journalctl -u myapp --since "10 minutes ago" --no-pager

# 5. Check resources (OOM Killer)
dmesg | grep -i "oom\|killed"

Scenario 3: High CPU Usage

# 1. Identify CPU-consuming processes
top -o %CPU -bn1 | head -15

# 2. Check threads of specific process
top -H -p $(pgrep myapp)

# 3. Trace system calls
strace -c -p $(pgrep myapp) -e trace=all

# 4. Load average history
sar -u 1 10

Scenario 4: Network Connection Issues

# 1. DNS check
dig api.example.com +short

# 2. Port connection test
nc -zv api.example.com 443

# 3. Route tracing
traceroute api.example.com

# 4. SSL certificate check
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -text -noout | grep -A2 "Validity"

Scenario 5: Memory Leak Investigation

# 1. Monitor memory usage trend
watch -n 5 'free -h'

# 2. Per-process memory usage
ps aux --sort=-%mem | head -10

# 3. Detailed memory for specific process
cat /proc/$(pgrep myapp)/status | grep -i "vm\|mem"

# 4. OOM Killer logs
dmesg -T | grep -i "oom"

Scenario 6: Slow Disk I/O

# 1. Check I/O wait
iostat -x 1 5

# 2. Find I/O heavy processes
iotop -oP

# 3. Disk performance test
dd if=/dev/zero of=testfile bs=1G count=1 oflag=direct

Scenario 7: SSH Connection Failure

# 1. Verbose debug mode
ssh -vvv user@server

# 2. SSH service status (on server)
sudo systemctl status sshd

# 3. Firewall check
sudo iptables -L -n | grep 22

# 4. Authentication log
sudo tail -50 /var/log/auth.log

Scenario 8: File Permission Issues

# 1. Check file permissions
ls -la /path/to/file
namei -l /path/to/file                   # Check entire path permissions

# 2. SELinux / AppArmor check
getenforce                               # SELinux status
ls -Z /path/to/file                      # SELinux context

# 3. ACL check
getfacl /path/to/file

Scenario 9: Attack Detection Through Log Analysis

# 1. Check abnormal login attempts
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head

# 2. Web server abnormal access check
awk '$9 == 404' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head

# 3. Concurrent connection count
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head

Scenario 10: Zombie Process

# 1. Identify zombie processes
ps aux | awk '$8 ~ /Z/ {print}'

# 2. Find parent process
ps -o ppid= -p ZOMBIE_PID

# 3. Clean up by restarting parent
kill -SIGCHLD PARENT_PID
# Or restart the parent process

16. Useful One-Liners

# Top 10 largest files in current directory
find . -type f -exec du -h {} + | sort -rh | head -10

# Kill process using a specific port instantly
kill $(lsof -t -i:8080)

# Find largest files in git repository
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort -snk2 | tail -10

# Measure server response time (10 iterations)
for i in $(seq 1 10); do curl -o /dev/null -s -w "%{time_total}\n" https://example.com; done

# Pretty print JSON
cat data.json | python3 -m json.tool
# or
cat data.json | jq .

# File encoding conversion
iconv -f EUC-KR -t UTF-8 input.txt > output.txt

# View all environment variables sorted
env | sort

# Total line count for specific file extension
find . -name "*.py" -exec wc -l {} + | tail -1

17. Interview Questions (15)

Q1. What is the difference between hard links and symbolic links?

Hard link: Points to the same inode. Accessible even if the original is deleted. Cannot cross filesystem boundaries. Cannot be used for directories.

Symbolic link: A separate inode pointing to a path. Becomes a broken link if the original is deleted. Can cross filesystems. Can be used for directories.

# Hard link: Same inode shared
ln original.txt hard.txt
ls -li original.txt hard.txt  # Same inode number

# Symbolic link: Different inode, path reference
ln -s original.txt sym.txt
ls -li original.txt sym.txt  # Different inode numbers
Q2. What is the difference between processes and threads?

Process: Has independent memory space, communicates via IPC (pipes, sockets). One process crash does not affect others.

Thread: Shares memory within the same process. Faster context switching, but one thread error can crash the entire process.

# Check processes with threads
ps -eLf | head   # List including threads (LWP)
# NLWP column shows thread count

# Thread count for a specific process
ls /proc/PID/task/ | wc -l
Q3. What do file permissions 755 and 644 mean?

755: rwxr-xr-x - Owner (read/write/execute), group (read/execute), others (read/execute). Typically used for directories and executable files.

644: rw-r--r-- - Owner (read/write), group (read), others (read). Typically used for regular files.

Calculation: r=4, w=2, x=1. Sum for each position (owner/group/others).

Q4. What is the difference between SIGTERM and SIGKILL?

SIGTERM (15): Requests graceful shutdown. The process can perform cleanup in its signal handler (close files, delete temp files). Default for kill PID.

SIGKILL (9): Kernel immediately force-kills the process. Cannot be caught or handled. No cleanup operations, risk of data loss. Use only as last resort.

Q5. When should you use grep, awk, and sed?
  • grep: Pattern searching (finding lines containing specific strings)
  • awk: Field-based data processing (column extraction, calculations, conditional filtering)
  • sed: Stream editing (string substitution, line deletion/insertion)

In practice, these three tools are often chained together with pipes:

# Analyze 5xx error URL frequency from logs
grep " 5[0-9][0-9] " access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
Q6. What is the difference between pipe (|) and redirect (>)?

Pipe (|): Connects stdout of one command to stdin of another. Inter-process communication.

Redirect (>): Sends command output to a file. Process-to-file communication.

# Pipe: ls output becomes grep input
ls -la | grep ".conf"

# Redirect: ls output goes to file
ls -la > filelist.txt
Q7. What is an inode?

An inode is a data structure in the filesystem that stores file metadata. It contains everything except the filename (owner, permissions, size, timestamps, data block locations). Directory entries map filenames to inode numbers.

# Check inode number
ls -i file.txt
stat file.txt           # Detailed inode info

# Check inode usage (file count limit)
df -i
Q8. Explain the three types of SSH tunneling.
  1. Local port forwarding (-L): Access remote service through local port. ssh -L 5432:db:5432 bastion - Connecting to local 5432 reaches db's 5432 through bastion.

  2. Remote port forwarding (-R): Access local service from remote. ssh -R 8080:localhost:3000 server - Connecting to server's 8080 reaches local 3000.

  3. Dynamic port forwarding (-D): Creates SOCKS proxy. ssh -D 1080 server - Uses local 1080 as SOCKS proxy routing all traffic through server.

Q9. What is a zombie process and how do you handle it?

A zombie process is one that has finished execution but whose parent has not yet collected its exit status via the wait() system call. It only occupies a PID and consumes no resources, but too many can exhaust the PID table.

Solution: Send SIGCHLD to the parent process, or kill the parent so init/systemd adopts and cleans up the orphaned processes.

ps aux | awk '$8=="Z"'           # Find zombie processes
kill -SIGCHLD PARENT_PID         # Notify parent about child termination
Q10. What is the /proc filesystem?

/proc is a virtual filesystem that provides kernel and process information in file form. It does not physically exist on disk; the kernel generates it in real-time.

cat /proc/cpuinfo        # CPU info
cat /proc/meminfo        # Memory info
cat /proc/PID/status     # Specific process status
cat /proc/PID/fd/        # Open file descriptors
cat /proc/loadavg        # System load
Q11. What are the file descriptor numbers for stdin, stdout, and stderr?
  • 0: stdin (standard input)
  • 1: stdout (standard output)
  • 2: stderr (standard error)
command > file.txt       # Redirect fd 1 (stdout) to file
command 2> error.log     # Redirect fd 2 (stderr) to file
command > file.txt 2>&1  # Redirect stderr to same place as stdout
command < input.txt      # Read fd 0 (stdin) from file
Q12. What is the difference between cron and at?

cron: Used for recurring scheduled tasks. Managed via crontab files.

# minute hour day month weekday command
crontab -e
0 2 * * * /backup/run.sh    # Every day at 2 AM
*/5 * * * * /check/health.sh # Every 5 minutes

at: Used for one-time tasks.

at now + 30 minutes
> /scripts/deploy.sh
> Ctrl+D
Q13. What is Load Average?

Load average is the average number of processes in runnable or waiting state. The uptime command shows 1-minute, 5-minute, and 15-minute averages.

Interpretation: Compare against CPU core count. On a 4-core system, load average 4.0 means 100% utilization, 8.0 means overloaded (processes waiting).

uptime                   # load average: 2.50, 3.10, 2.80
nproc                    # Check CPU core count
Q14. What is swap memory? Why should servers be careful with it?

Swap is disk space used as memory when RAM is exhausted. Disk I/O is thousands of times slower than RAM, so heavy swap usage causes severe performance degradation.

free -h                  # Check swap usage
swapon --show            # Swap device info
vmstat 1                 # High si/so values indicate heavy swap usage
cat /proc/sys/vm/swappiness  # Swap tendency (0-100, lower prefers RAM)
Q15. What does set -euo pipefail do?

Safety guard for Bash scripts:

  • -e (errexit): Script exits immediately when a command fails (non-zero exit)
  • -u (nounset): Error on undeclared variable usage
  • -o pipefail: Detects failures in middle of pipeline

Without these options, errors are silently ignored, leading to unexpected behavior. Always recommended for production scripts.


18. Quiz

Q1. What is the output of: echo "Hello" | tee output.txt | wc -c

Answer: 6

tee writes stdin to output.txt while also passing it to stdout. wc -c counts bytes: "Hello\n" = 6 bytes.

Q2. In chmod 4755 script.sh, what does the 4 mean?

Answer: SetUID bit

4 is the SetUID (Set User ID) bit. When executed, the file runs with the file owner's permissions. For example, /usr/bin/passwd is owned by root with SetUID set, allowing regular users to change passwords. SetGID is 2, Sticky Bit is 1.

Q3. Which is the correct way to monitor a file in real-time while filtering for a specific pattern?

A) grep "ERROR" < tail -f app.log B) tail -f app.log | grep "ERROR" C) tail -f app.log > grep "ERROR" D) cat app.log | tail -f | grep "ERROR"

Answer: B

Pipe tail -f output to grep. A is a syntax error. C misuses redirect. D reads the whole file with cat first, making tail -f meaningless.

Q4. What actually happens with ssh -L 3306:db-server:3306 bastion?

Answer: Connecting to local port 3306 routes through the SSH connection via bastion server to reach db-server's port 3306 (MySQL). You can access the remote DB with mysql -h 127.0.0.1 -P 3306. Communication is encrypted via SSH.

Q5. Find the bug in this script.
#!/bin/bash
for f in $(ls *.txt); do
    mv "$f" "${f%.txt}.md"
done

Answer: Using ls output in a for loop breaks when filenames contain spaces. The correct approach:

#!/bin/bash
for f in *.txt; do
    [ -e "$f" ] || continue
    mv "$f" "${f%.txt}.md"
done

Use glob patterns directly and check for existence when no files match.


19. References

Official Documentation

  1. GNU Coreutils Manual - Core utilities official docs
  2. GNU Bash Manual - Bash official reference
  3. The Linux Documentation Project - Comprehensive Linux documentation
  4. man7.org Linux Manual Pages - Online Linux man pages
  5. tmux Wiki - tmux official wiki

Learning Resources

  1. Linux Journey - Beginner-friendly Linux learning
  2. OverTheWire Bandit - Learn Linux through games
  3. Vim Adventures - Learn Vim through games
  4. ExplainShell - Enter a command and get each part explained
  5. ShellCheck - Bash script linter/analyzer

Books

  1. The Linux Command Line (William Shotts) - The Linux CLI bible
  2. Linux Pocket Guide (Daniel J. Barrett) - Quick reference
  3. Bash Cookbook (Carl Albing) - Bash recipe collection
  4. sed and awk (Dale Dougherty) - Advanced text processing

Cheat Sheets

  1. devhints.io/bash - Bash cheat sheet
  2. tmux Cheat Sheet - tmux shortcuts
  3. Vim Cheat Sheet - Vim commands reference