LinuxLab · Linux Mint 22.3 XFCE 0%
Chapter 01

Linux Mint 22.3 XFCE — 터미널 완전 정복

XFCE 데스크톱 기반 Linux Mint 22.3에서 파이썬 개발자가 필요한 모든 리눅스 기초를 다룹니다.

1-1

🐧리눅스 & Linux Mint 22.3 XFCE란

Linux Mint 22.3은 2025년 출시된 Ubuntu 24.04 LTS 기반 배포판입니다. 코드명 "Wilma"이며, XFCE 4.18 데스크톱 환경을 사용합니다.

ℹ️
XFCE vs Cinnamon vs MATE: Linux Mint는 3가지 에디션이 있습니다. XFCE는 가장 가볍고 빠릅니다 (RAM 300~500MB). 구형 PC나 개발용 VM에 이상적입니다. Cinnamon은 무겁지만 화려하고, MATE는 중간입니다.

파이썬 개발자에게 Linux Mint XFCE가 좋은 이유:

  • 서버 환경 일치 — Django/FastAPI 배포 서버(Ubuntu 기반)와 동일한 패키지 관리자, 동일한 명령어
  • 가벼움 — XFCE는 RAM을 적게 써서 파이썬 서버, Docker, DB를 동시에 돌리기 편함
  • apt 패키지 — pip + apt 조합으로 모든 개발 환경 세팅 가능
  • LTS 기반 — Ubuntu 24.04 기반으로 2029년까지 보안 업데이트 보장
항목Linux Mint 22.3 XFCE비고
기반Ubuntu 24.04 LTS (Noble)apt 완전 호환
커널Linux 6.8.x최신 하드웨어 지원
Python3.12.x (기본 내장)pip3, venv 포함
GCC13.x (apt install 필요)build-essential
RAM 사용~400MB (유휴 시)VM에도 쾌적
기본 터미널xfce4-terminalCtrl+Alt+T 설정 가능
기본 에디터mousepadnano/vim 별도 설치
1-2

⌨️터미널 열기 & 첫 명령 (XFCE)

XFCE에서 터미널을 여는 방법:

  • 바탕화면 우클릭터미널 열기
  • 애플리케이션 메뉴 → 시스템 → Xfce Terminal
  • 단축키 설정: 설정 → 키보드 → 애플리케이션 단축키 → xfce4-terminalCtrl+Alt+T
  • 파일관리자(Thunar) 주소창에서 Ctrl+Alt+T (Thunar 내 위치에서 터미널)
💡
XFCE 터미널 단축키 설정법: 설정 매니저 → 키보드 → 애플리케이션 단축키 탭 → 추가 버튼 → 명령에 xfce4-terminal 입력 → Ctrl+Alt+T 누르기
bash — 첫 명령어 & 시스템 정보
$ lsb_release -a
No LSB modules are available.
Distributor ID: Linuxmint
Description:    Linux Mint 22.3
Release:        22.3
Codename:       wilma

$ uname -r           # 커널 버전
6.8.0-51-generic

$ python3 --version
Python 3.12.3

$ echo $XDG_CURRENT_DESKTOP   # 데스크톱 환경 확인
XFCE

$ free -h             # 메모리 사용량
               total    used    free
Mem:            7.7Gi   412Mi   6.8Gi
💡
핵심 단축키: Tab 자동완성 / ↑↓ 명령 기록 / Ctrl+R 기록 검색 / Ctrl+C 중단 / Ctrl+D 종료 / Ctrl+L 화면 지우기 / Ctrl+Shift+C xfce4-terminal 복사 / Ctrl+Shift+V xfce4-terminal 붙여넣기
Linux Mint 22.3의 기반이 되는 Ubuntu LTS 버전은?
1-3

📁파일시스템 구조

리눅스는 모든 것이 파일입니다. 하나의 루트 /에서 모든 경로가 시작됩니다.

/ ← 루트 (최상위) ├── home/ ← 사용자 홈 디렉터리들 │ └── user/ ← 내 홈 (~와 동일) │ ├── Desktop/ ← XFCE 바탕화면 │ ├── Documents/ │ ├── Downloads/ │ └── projects/ ← 개발 프로젝트 여기에 ├── etc/ ← 시스템 설정 (nginx.conf, hosts 등) ├── usr/ │ ├── bin/ ← 실행파일 (python3, gcc, ls 등) │ ├── lib/ ← 라이브러리 │ └── local/ ← 사용자 직접 설치 프로그램 ├── var/ │ └── log/ ← 시스템 로그 (syslog, apt 등) ├── tmp/ ← 임시파일 (재부팅 시 삭제) ├── dev/ ← 장치파일 (USB, 디스크 등) └── proc/ ← 프로세스 정보 (가상FS)
bash — 경로 탐색
$ pwd                    # 현재 위치 (Print Working Directory)
/home/user
$ cd /etc && pwd
/etc
$ cd ~                   # 홈으로
$ cd -                   # 이전 위치 (토글)
$ cd ~/projects/myapp   # ~ 확장

# 경로 규칙
# /home/user/projects   절대경로 (/ 로 시작)
# ./src/main.py         상대경로 (현재 위치 기준)
# ../config.py          상위 디렉터리의 파일
# ~                     /home/현재사용자

# XFCE Thunar 파일관리자에서 경로 직접 입력: Ctrl+L
1-4

🔧필수 명령어 총정리

명령어설명예시
ls -la파일 목록 (상세+숨김)ls -lhS (크기순)
cd디렉터리 이동cd ~/projects
pwd현재 경로 출력pwd
mkdir -p폴더 생성 (중간경로 포함)mkdir -p src/utils
rm -rf삭제 (⚠️ 주의)rm -rf build/
cp -r복사 (디렉터리)cp -r src/ backup/
mv이동/이름 변경mv old.py new.py
cat파일 내용 출력cat -n main.py
less페이지 단위 보기 (q 종료)less /var/log/syslog
head / tail앞/뒷부분 출력tail -f app.log
grep -rn패턴 검색 (재귀+줄번호)grep -rn "def " .
find파일 찾기find . -name "*.py"
touch빈 파일 생성touch main.py
wc -l줄 수 세기wc -l main.py
sort / uniq정렬 / 중복 제거sort file.txt | uniq -c
diff파일 비교diff old.py new.py
tree디렉터리 구조 트리tree -L 2 myproject/
history명령 기록history | grep git
man매뉴얼 (q 종료)man grep
bash — 파이프라인 & 리다이렉션
# | 파이프: 앞 출력 → 다음 입력
$ ls -la | grep ".py" | wc -l     # .py 파일 수
$ cat access.log | grep "404" | sort | uniq -c

# 리다이렉션
$ python3 main.py > out.txt        # stdout 저장
$ python3 main.py >> log.txt       # stdout 추가
$ python3 main.py 2> err.log       # stderr만
$ python3 main.py &> all.log       # stdout+stderr

# tee: 화면 + 파일 동시
$ python3 main.py | tee log.txt
⚠️
rm -rf 주의! 리눅스에는 휴지통 없음. 삭제된 파일은 복구 거의 불가. 특히 rm -rf *, rm -rf /는 절대 금지. 항상 경로를 먼저 echo로 확인하세요.
1-5

🔒파일 권한 (chmod)

모든 파일은 소유자(u), 그룹(g), 기타(o) 3자에 대해 읽기(r=4), 쓰기(w=2), 실행(x=1) 권한을 가집니다.

ls -la 권한 읽기
-rwxr-xr--  1 user group 2048 May 6 script.sh
 ↑↑↑↑↑↑↑↑↑
 │└──┤└──┤└──┘
 │  u   g   o
 │ rwx r-x r--
 │  7   5   4
 └─ 파일타입: - 파일, d 디렉터리, l 심볼릭링크
bash — chmod 실전
$ chmod 755 run.sh        # rwxr-xr-x : 실행파일 표준
$ chmod 644 config.py     # rw-r--r-- : 일반 파일
$ chmod 600 .env           # rw------- : API키 등 비밀파일
$ chmod 700 scripts/       # rwx------ : 내 디렉터리만
$ chmod +x myscript.py    # 실행권한 추가
$ chmod -R 755 myproject/  # 재귀 적용

# 파이썬 스크립트 직접 실행하기
$ nano hello.py
# 첫 줄에 추가: #!/usr/bin/env python3
$ chmod +x hello.py
$ ./hello.py           # python3 없이 실행!
팀원이 읽을 수 있지만 수정은 본인만 가능한 파이썬 파일의 권한 숫자는?
1-6

📦패키지 관리 (apt) — Linux Mint 22.3

bash — apt 완전 가이드
# 패키지 목록 갱신 (항상 먼저)
$ sudo apt update

# 전체 업그레이드
$ sudo apt upgrade

# 개발자 필수 패키지 한 번에
$ sudo apt install -y \
    git curl wget tree htop vim \
    python3-pip python3-venv python3-dev \
    build-essential gcc g++ make gdb \
    net-tools nmap

# 패키지 검색/정보
$ apt search python3
$ apt show python3
$ apt list --installed | grep python

# 제거
$ sudo apt remove 패키지명
$ sudo apt purge 패키지명   # 설정파일까지
$ sudo apt autoremove       # 불필요한 의존성

# Linux Mint 전용: mintinstall (소프트웨어 매니저)
$ mintinstall    # GUI 소프트웨어 센터

# flatpak (snap 대신 Mint는 Flatpak 권장)
$ flatpak install flathub org.gimp.GIMP
1-7

✏️텍스트 편집 (nano / vim / mousepad)

XFCE의 기본 GUI 에디터는 Mousepad입니다. 터미널에서는 nano(쉬움) 또는 vim(강력)을 사용합니다.

bash — 에디터 선택
# nano (입문자 추천)
$ nano hello.py
# ^O 저장  ^X 종료  ^W 검색  ^\ 치환  ^K 줄 삭제  ^U 붙여넣기

# vim (강력, 학습 필요)
$ vim main.py
# i → Insert모드  Esc → Normal  :wq 저장종료  :q! 강제종료
# dd 줄삭제  yy 복사  p 붙여넣기  /검색어 검색

# Mousepad (XFCE GUI 에디터)
$ mousepad hello.py &    # & : 백그라운드 실행 (터미널 계속 사용)

# VS Code (권장 개발 에디터)
$ sudo apt install snapd
# 또는 공식 .deb 다운로드: code.visualstudio.com
$ wget -q https://packages.microsoft.com/keys/microsoft.asc \
    | gpg --dearmor > /etc/apt/keyrings/microsoft.gpg
$ sudo apt install code
1-8

⚙️프로세스 & 시스템 관리

bash — 프로세스 & 자원 관리
# 프로세스 목록
$ ps aux | grep python     # 파이썬 프로세스만
$ pgrep -la python        # 이름으로 PID 검색

# 실시간 모니터
$ htop                    # 컬러 모니터 (추천)
$ top                     # 기본 (q 종료)

# XFCE 작업 관리자
$ xfce4-taskmanager &     # GUI 작업 관리자

# 종료
$ kill -9 1234            # PID로 강제 종료
$ pkill python            # 이름으로 종료
# Ctrl+C  현재 실행 중단
# Ctrl+Z  백그라운드로 (fg로 복귀)

# 백그라운드 실행
$ python3 server.py &     # & : 백그라운드
$ nohup python3 server.py > server.log 2>&1 &  # 로그아웃 후에도
$ jobs                    # 백그라운드 작업 목록

# 시스템 자원
$ free -h                # 메모리
$ df -h                  # 디스크 파티션
$ du -sh * | sort -h   # 현재 폴더 크기 정렬
$ lsblk                  # 디스크 블록 장치
파이썬 서버 스크립트를 SSH 접속 종료 후에도 계속 실행되게 하는 명령은?
1-9

🌿환경변수 & .bashrc 설정

bash — ~/.bashrc 개발자 설정
$ nano ~/.bashrc

# ── 개발자 alias 모음 ─────────────────────────
alias ll='ls -la --color=auto'
alias la='ls -A'
alias py='python3'
alias pip='pip3'
alias gs='git status'
alias gl='git log --oneline --graph --all'
alias gp='git push'
alias ..='cd ..'
alias ...='cd ../..'
alias myip='curl -s ifconfig.me'
alias ports='ss -tulnp'
alias update='sudo apt update && sudo apt upgrade -y'

# ── 환경변수 ─────────────────────────────────
export EDITOR="nano"
export PYTHONDONTWRITEBYTECODE=1   # .pyc 생성 안 함
export PYTHONUNBUFFERED=1          # 출력 버퍼링 없음
export PATH="$HOME/.local/bin:$PATH"

# ── 프롬프트 커스터마이즈 ────────────────────
# 현재 git 브랜치 표시
parse_git_branch() {
    git branch 2>/dev/null | grep '*' | sed 's/* //'
}
export PS1='\[\033[0;32m\]\u@\h\[\033[0m\]:\[\033[0;34m\]\w\[\033[0;33m\]$(b=$(parse_git_branch); [ -n "$b" ] && echo " ($b)")\[\033[0m\]\$ '

# ── 적용 ────────────────────────────────────
$ source ~/.bashrc
python3 — 환경변수 읽기 (.env 패턴)
import os
from dotenv import load_dotenv  # pip install python-dotenv

load_dotenv()  # .env 파일 자동 로드

DEBUG = os.getenv('DEBUG', 'False') == 'True'
SECRET_KEY = os.environ['SECRET_KEY']  # 없으면 KeyError
DB_URL = os.getenv('DATABASE_URL', 'sqlite:///db.sqlite3')
1-10

📜셸 스크립트 기초

bash — setup_dev.sh (개발환경 자동세팅 스크립트)
#!/bin/bash
# Linux Mint 22.3 XFCE 개발환경 자동 세팅
set -e  # 오류 시 즉시 종료

PROJECT="$1"                       # 첫 번째 인자 = 프로젝트명
PYTHON=python3

# 인자 확인
if [ -z "$PROJECT" ]; then
    echo "사용법: $0 <프로젝트명>"
    exit 1
fi

log() { echo "[$(date '+%H:%M:%S')] $1"; }

# 개발 패키지 설치
log "시스템 패키지 설치 중..."
sudo apt update -q
sudo apt install -y git python3-pip python3-venv python3-dev build-essential

# 프로젝트 폴더 생성
if [ -d "$PROJECT" ]; then
    echo "이미 존재: $PROJECT"
    exit 1
fi

mkdir "$PROJECT"
cd "$PROJECT"

# 가상환경 생성 & 활성화
log "가상환경 생성 중..."
$PYTHON -m venv venv
source venv/bin/activate

# 기본 패키지 설치
pip install --upgrade pip -q
pip install requests python-dotenv -q

# .gitignore 생성
cat > .gitignore << 'EOF'
venv/
__pycache__/
*.pyc
.env
*.log
.DS_Store
EOF

# README 생성
echo "# $PROJECT" > README.md

# git 초기화
git init
git add .
git commit -m "initial commit"

log "✓ $PROJECT 세팅 완료! 'source $PROJECT/venv/bin/activate' 로 활성화"
bash — 실행
$ chmod +x setup_dev.sh
$ ./setup_dev.sh mydjango
[10:23:01] 시스템 패키지 설치 중...
[10:23:15] 가상환경 생성 중...
[10:23:18] ✓ mydjango 세팅 완료!
1-11

🔍grep · sed · awk — 텍스트 처리 3대장

bash — grep 패턴 검색
$ grep -rn "import django" .          # 재귀+줄번호
$ grep -i "error" app.log             # 대소문자 무시
$ grep -v "DEBUG" app.log             # 제외
$ grep -c "ERROR" app.log             # 개수만
$ grep -A3 "Exception" app.log        # 매칭 후 3줄 더
$ grep -E "error|warning|critical" log  # OR
$ grep -rn "TODO\|FIXME" --include="*.py" .
bash — sed & awk
# sed — 스트림 에디터
$ sed 's/DEBUG=True/DEBUG=False/g' settings.py
$ sed -i 's/localhost/0.0.0.0/g' config.py   # 파일 직접 수정
$ sed '/^#/d' config.py               # # 주석 줄 삭제
$ sed '/^$/d' file.py                 # 빈 줄 삭제
$ sed -n '10,20p' file.py             # 10~20번 줄만 출력

# awk — 컬럼 처리
$ ps aux | awk '{print $2, $11}'        # PID, 명령어
$ df -h | awk '/\/$/ {print $5}'       # 루트 파티션 사용률
$ awk -F',' 'NR>1 {sum+=$3} END {print sum}' data.csv
$ awk -F':' '{print $1}' /etc/passwd    # 계정명 목록
app.log에서 "ERROR"가 포함된 줄의 수를 세는 명령은?
1-12

🕐cron — 작업 예약

bash — crontab 완전 가이드
$ crontab -e        # 편집 (처음 실행 시 에디터 선택 → nano 선택)
$ crontab -l        # 현재 목록 확인
$ crontab -r        # 전체 삭제

# 형식: 분 시 일 월 요일  명령어
# *  *  *  *  *   command
# │  │  │  │  └── 요일 (0=일, 1=월 ... 6=토)
# │  │  │  └───── 월 (1-12)
# │  │  └──────── 일 (1-31)
# │  └─────────── 시 (0-23)
# └────────────── 분 (0-59)

# 예시
0 6 * * *    /home/user/venv/bin/python3 /home/user/daily.py
*/5 * * * *  /home/user/scripts/monitor.sh >> /home/user/cron.log 2>&1
0 9 * * 1    /home/user/venv/bin/python3 /home/user/weekly.py
0 0 1 * *    /home/user/scripts/backup.sh
@reboot      /home/user/scripts/startup.sh  # 재부팅 시 1회

# cron 서비스 상태
$ sudo systemctl status cron
💡
cron에서 가상환경 사용: cron의 PATH가 다르므로 /home/user/myproject/venv/bin/python3처럼 절대경로를 사용하거나, 스크립트 첫 줄에 source /home/user/myproject/venv/bin/activate를 포함하세요.
1-13

🔐SSH & 원격 접속

bash — SSH 완전 가이드
# 기본 접속
$ ssh user@192.168.1.100
$ ssh -i ~/.ssh/mykey.pem ubuntu@54.180.10.95

# SSH 키 생성 (비밀번호 없는 접속)
$ ssh-keygen -t ed25519 -C "myemail@gmail.com"
# 생성: ~/.ssh/id_ed25519 (비공개), ~/.ssh/id_ed25519.pub (공개)

# 공개키 서버에 등록
$ ssh-copy-id user@server
# 이제 비밀번호 없이 접속!

# ~/.ssh/config 설정 (단축 접속)
$ nano ~/.ssh/config
Host myserver
    HostName 54.180.10.95
    User ubuntu
    IdentityFile ~/.ssh/mykey.pem

$ ssh myserver        # 이제 단축키로 접속

# 파일 전송
$ scp local.py user@server:~/
$ scp -r myproject/ user@server:~/
$ rsync -avz --exclude=venv/ myproject/ user@server:~/myproject/
1-14

🌐네트워크 명령어

bash — 네트워크 진단 & API 테스트
# IP 확인
$ ip addr | grep "inet "       # 로컬 IP
$ curl ifconfig.me             # 공인 IP
$ hostname -I                  # IP 목록

# 연결 테스트
$ ping -c 4 8.8.8.8
$ ss -tulnp                   # 열린 포트 목록
$ ss -tulnp | grep ":8000"   # 8000번 포트 사용중?

# curl — Django API 테스트에 유용
$ curl http://localhost:8000/api/users/    # GET
$ curl -X POST \
     -H "Content-Type: application/json" \
     -H "Authorization: Token abc123" \
     -d '{"name":"홍길동","email":"hong@test.com"}' \
     http://localhost:8000/api/users/
$ curl -s http://localhost:8000/api/ | python3 -m json.tool
Chapter 02

Python — 리눅스에서 시작하는 파이썬

Linux Mint 22.3 XFCE에서 가상환경부터 OOP, subprocess, 데코레이터까지 실전 파이썬을 완성합니다.

2-1

🐍Python 설치 & 환경 확인

Linux Mint 22.3에는 Python 3.12.x가 기본 내장되어 있습니다.

bash — Python 환경 세팅
$ python3 --version
Python 3.12.3

# 필수 패키지 설치
$ sudo apt install python3-pip python3-venv python3-dev

# 인터랙티브 셸 (REPL)
$ python3
>>> print("Hello, Linux Mint 22.3!")
Hello, Linux Mint 22.3!
>>> import sys; print(sys.version)
3.12.3 (main, Apr 10 2024, 05:33:47)
>>> exit()

# 스크립트 실행 방법들
$ python3 main.py
$ python3 -c "print('한 줄 실행')"
$ python3 -m http.server 8080   # 빠른 파일 서버
$ python3 -i main.py             # 실행 후 REPL 유지
2-2

🏠가상환경 (venv) 완전 정복

bash — venv 전체 흐름
$ mkdir myproject && cd myproject
$ python3 -m venv venv
$ source venv/bin/activate
(venv) user@linuxmint:~/myproject$

(venv) $ pip install --upgrade pip
(venv) $ pip install django requests pillow
(venv) $ pip freeze > requirements.txt
(venv) $ pip install -r requirements.txt
(venv) $ deactivate

# .gitignore에 추가
$ cat >> .gitignore << 'EOF'
venv/
__pycache__/
*.pyc
.env
EOF
Linux Mint XFCE에서 가상환경을 활성화하는 명령어는?
2-3

📝변수 & 자료형

python3 — types.py
# 기본 자료형
name = "Linux Mint"        # str
version = 22.3            # float
count = 42                # int
active = True             # bool
nothing = None            # NoneType

# f-string (Python 3.6+, 권장 포맷)
print(f"OS: {name} v{version:.1f}")
print(f"카운트: {count:,}")         # 천 단위 콤마
print(f"{'left':<10}|")           # 왼쪽 정렬 10칸

# 문자열 메서드
s = "  Hello, Linux!  "
print(s.strip())            # 공백 제거
print(s.lower().strip())
print(s.replace("Linux", "Mint"))
print(s.split(","))         # 분리
print(",".join(["a", "b", "c"]))  # 합치기
print("linux" in s.lower()) # True

# 형변환
print(int("42"), float("3.14"), str(100))
print(bool(0), bool(""), bool([]))  # 모두 False
print(bool(1), bool("a"), bool([0]))  # 모두 True
2-4

🔀조건문 & 반복문

python3 — control.py
# match-case (Python 3.10+)
status = 404
match status:
    case 200: print("OK")
    case 404: print("Not Found")
    case _:   print("Other")

# enumerate + zip
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]

for i, (name, score) in enumerate(zip(names, scores), 1):
    print(f"{i}. {name}: {score}점")

# 컴프리헨션
squares = [x**2 for x in range(10) if x % 2 == 0]
score_map = {n: s for n, s in zip(names, scores)}
unique = {n.upper() for n in names}       # set
gen = (sum(x**2 for x in range(1000000)))  # 제너레이터

# sorted / filter / map
nums = [3, 1, 4, 1, 5, 9]
print(sorted(nums, reverse=True))
print(list(filter(lambda x: x > 3, nums)))
print(list(map(lambda x: x * 2, nums)))
2-5

🔧함수 & 모듈 (os, pathlib, sys)

python3 — functions.py
import os, sys
from pathlib import Path
from datetime import datetime

def greet(name: str, greeting: str = "안녕하세요") -> str:
    """간단한 인사 함수."""
    return f"{greeting}, {name}님!"

def stats(*args: float) -> dict:
    return {"합계": sum(args), "평균": sum(args)/len(args)}

def create_user(**kwargs) -> dict:
    return {"created_at": datetime.now().isoformat(), **kwargs}

# os 모듈 — Linux에서 핵심
print(os.getcwd())               # 현재 디렉터리
print(os.listdir("."))           # 파일 목록
os.makedirs("output/logs", exist_ok=True)
print(os.environ.get("HOME"))    # 환경변수
print(os.cpu_count())            # CPU 코어 수

# pathlib — 현대적 경로 처리
p = Path("~/projects").expanduser()
for f in p.rglob("*.py"):
    print(f.stem, f.stat().st_size)

path = Path("/home/user/main.py")
print(path.parent, path.stem, path.suffix)
new = path.with_suffix(".txt")

# sys
print(sys.argv)          # 명령줄 인자
print(sys.platform)      # 'linux'
sys.exit(0)              # 종료
2-6

📂파일 입출력 & pip 패키지

python3 — file_io.py
import json, csv
from pathlib import Path

# 텍스트
Path("out.txt").write_text("Hello\n두 번째 줄\n", encoding="utf-8")
content = Path("out.txt").read_text(encoding="utf-8")
lines = content.splitlines()

# JSON
data = {"name": "홍길동", "scores": [85, 92], "active": True}
Path("data.json").write_text(
    json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8"
)
loaded = json.loads(Path("data.json").read_text())

# CSV
with open("students.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "score"])
    writer.writeheader()
    writer.writerows([{"name": "Alice", "score": 95}])

# pip 명령
# pip install 패키지           설치
# pip install -r requirements  일괄 설치
# pip freeze > requirements.txt 목록 저장
# pip list                     설치 목록
# pip show 패키지              상세 정보
# pip uninstall 패키지         제거
2-7

📚리스트 · 딕셔너리 심화

python3 — collections.py
from collections import defaultdict, Counter, deque

# Counter — 빈도 분석
words = ["apple", "banana", "apple", "cherry", "apple"]
cnt = Counter(words)
print(cnt.most_common(2))  # [('apple', 3), ('banana', 1)]

# defaultdict — KeyError 없는 딕셔너리
groups: defaultdict = defaultdict(list)
for team, name in [("A","Alice"),("B","Bob"),("A","Carol")]:
    groups[team].append(name)

# 딕셔너리 심화
config = {"debug": True, "port": 8000}
override = {"port": 9000, "workers": 4}
merged = config | override          # Python 3.9+ 병합

# 구조분해 할당
first, *rest = [1, 2, 3, 4]
*head, last  = [1, 2, 3, 4]

# dict 언패킹으로 함수 호출
def connect(host, port): print(f"{host}:{port}")
connect(**config)

# 리스트 슬라이싱
nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4])    # [1,2,3]
print(nums[-3:])   # [3,4,5] 마지막 3개
print(nums[::-1])  # [5,4,3,2,1,0] 역순
print(nums[::2])   # [0,2,4] 2칸 간격
2-8

🏛️클래스 & 객체지향

python3 — oop.py
from dataclasses import dataclass, field
from datetime import datetime

class Animal:
    kingdom = "Animalia"   # 클래스 변수

    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def speak(self) -> str:
        return "..."

    def __repr__(self): return f"Animal({self.name!r})"
    def __str__(self):  return f"{self.name} ({self.age}세)"

class Dog(Animal):                  # 상속
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self.breed = breed

    def speak(self): return f"{self.name}: 멍멍!"

# dataclass — 보일러플레이트 자동 생성
@dataclass
class User:
    name: str
    email: str
    age: int = 0
    tags: list = field(default_factory=list)
    created_at: str = field(
        default_factory=lambda: datetime.now().isoformat()
    )

    def is_adult(self) -> bool: return self.age >= 18

dog = Dog("바둑이", 3, "진도")
print(dog.speak())
print(isinstance(dog, Animal))    # True

user = User("홍길동", "hong@test.com", age=25)
print(user, user.is_adult())
파이썬 dataclass에서 가변 기본값(리스트, 딕셔너리)을 올바르게 설정하는 방법은?
2-9

🛡️예외처리 (try / except)

python3 — exceptions.py
import logging

logging.basicConfig(level=logging.INFO,
    format='%(asctime)s %(levelname)s %(message)s',
    handlers=[logging.FileHandler('app.log'), logging.StreamHandler()])
logger = logging.getLogger(__name__)

# 기본 구조
try:
    x = int(input("숫자: "))
    result = 100 / x
except ValueError:
    logger.error("숫자가 아닙니다")
except ZeroDivisionError:
    logger.error("0으로 나눌 수 없음")
except Exception as e:
    logger.exception(f"예상치 못한 오류: {e}")
else:
    print(f"결과: {result}")  # 예외 없을 때만
finally:
    print("항상 실행")       # DB 연결 종료 등에 사용

# 사용자 정의 예외
class AppError(Exception):
    def __init__(self, msg: str, code: int = 500):
        super().__init__(msg)
        self.code = code

class ValidationError(AppError): pass

def validate_age(age: int):
    if not isinstance(age, int):
        raise TypeError("나이는 정수")
    if age < 0 or age > 150:
        raise ValidationError(f"유효하지 않은 나이: {age}", code=400)
2-10

subprocess — 파이썬에서 리눅스 명령 실행

python3 — subprocess_demo.py
import subprocess

# 기본 실행 (권장)
result = subprocess.run(
    ["ls", "-la"],
    capture_output=True,   # stdout/stderr 캡처
    text=True,              # 문자열로 반환
    cwd="/home/user"        # 실행 디렉터리
)
print(result.stdout)
print(result.returncode)   # 0=성공

# 실패 시 예외 자동 발생
try:
    subprocess.run(["git", "pull"], check=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"실패: {e.stderr}")

# 셸 명령 (파이프 포함)
result = subprocess.run(
    "ps aux | grep python | awk '{print $2}'",
    shell=True, capture_output=True, text=True
)

# 실용 예시: 배포 자동화
def deploy(branch="main"):
    cmds = [
        ["git", "pull", "origin", branch],
        ["pip", "install", "-r", "requirements.txt", "-q"],
        ["python3", "manage.py", "migrate"],
        ["systemctl", "restart", "myapp"],
    ]
    for cmd in cmds:
        r = subprocess.run(cmd, capture_output=True, text=True)
        if r.returncode != 0:
            print(f"실패: {' '.join(cmd)}\n{r.stderr}")
            return False
    return True
2-11

🖥️argparse — CLI 도구 만들기

python3 — linuxinfo.py (실전 CLI 도구)
#!/usr/bin/env python3
"""Linux Mint 시스템 정보 출력 도구."""
import argparse, subprocess, os, sys
from pathlib import Path

def get_os_info() -> dict:
    result = subprocess.run(["lsb_release", "-a"],
                            capture_output=True, text=True)
    info = {}
    for line in result.stdout.splitlines():
        if ":" in line:
            k, v = line.split(":", 1)
            info[k.strip()] = v.strip()
    return info

def get_memory() -> str:
    r = subprocess.run(["free", "-h"], capture_output=True, text=True)
    return r.stdout

def count_py_files(path: str) -> int:
    return len(list(Path(path).rglob("*.py")))

def main():
    parser = argparse.ArgumentParser(description="Linux Mint 시스템 정보")
    parser.add_argument("--os", action="store_true", help="OS 정보")
    parser.add_argument("--mem", action="store_true", help="메모리 정보")
    parser.add_argument("--count-py", metavar="PATH", help=".py 파일 수")
    parser.add_argument("--version", action="version", version="1.0.0")
    args = parser.parse_args()

    if args.os:
        info = get_os_info()
        print(f"OS: {info.get('Description','?')}")
    if args.mem:
        print(get_memory())
    if args.count_py:
        n = count_py_files(args.count_py)
        print(f".py 파일: {n}개")
    if not any([args.os, args.mem, args.count_py]):
        parser.print_help()

if __name__ == "__main__":
    main()
bash — 사용
$ chmod +x linuxinfo.py
$ ./linuxinfo.py --os
OS: Linux Mint 22.3
$ ./linuxinfo.py --mem
$ ./linuxinfo.py --count-py ~/projects
.py 파일: 142개
$ ./linuxinfo.py --help
2-12

🎨데코레이터 & 제너레이터

python3 — advanced.py
import time, functools
from typing import Callable, Any

# ── 데코레이터 ───────────────────────────────
def timer(func: Callable) -> Callable:
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        t = time.perf_counter()
        result = func(*args, **kwargs)
        print(f"[timer] {func.__name__}: {time.perf_counter()-t:.4f}s")
        return result
    return wrapper

def retry(max_attempts=3, delay=1.0):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(max_attempts):
                try: return func(*args, **kwargs)
                except Exception as e:
                    print(f"시도 {i+1}/{max_attempts}: {e}")
                    if i < max_attempts-1: time.sleep(delay)
            raise RuntimeError("최대 재시도 초과")
        return wrapper
    return decorator

@timer
def slow_task(n): time.sleep(0.1); return sum(range(n))

@retry(max_attempts=3, delay=0.5)
def fetch_data(url): pass  # 실제론 requests.get(url)

# ── 제너레이터 ───────────────────────────────
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

def read_large_log(path: str):
    """대용량 로그를 한 줄씩 읽는 제너레이터."""
    with open(path, encoding="utf-8") as f:
        for line in f:
            yield line.strip()

# 사용
fib = fibonacci()
first10 = [next(fib) for _ in range(10)]
print(first10)   # [0,1,1,2,3,5,8,13,21,34]

# 에러 라인만 추출 (메모리 효율)
error_lines = [
    l for l in read_large_log("app.log")
    if "ERROR" in l
]
데코레이터에서 @functools.wraps(func)를 쓰는 이유는?
2-13

🔎정규표현식 (re 모듈)

python3 — regex.py
import re

text = "이메일: hong@example.com, 전화: 010-1234-5678, 날짜: 2026-05-06"

# 기본 함수
re.search(r'\d+', text)            # 첫 매칭
print(re.findall(r'\d+', text))    # 모든 숫자
print(re.sub(r'\d{4}', '****', text))  # 4자리 숫자 마스킹

# 이메일 추출
email_pat = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
print(re.findall(email_pat, text))  # ['hong@example.com']

# 한국 전화번호
phone_pat = r'0\d{1,2}[-.]?\d{3,4}[-.]?\d{4}'
print(re.findall(phone_pat, text))

# 날짜 추출 + 그룹
m = re.search(r'(\d{4})-(\d{2})-(\d{2})', text)
if m:
    year, month, day = m.groups()
    print(f"{year}년 {month}월 {day}일")

# 컴파일 (반복 사용 시 성능 향상)
pat = re.compile(r'\d{4}-\d{2}-\d{2}')
print(pat.findall("2026-01-01, 2026-12-31"))

# 핵심 패턴
# .  아무문자  \d 숫자  \w 문자/숫자/_  \s 공백
# *  0회이상   +  1회이상   ?  0또는1
# ^  시작  $  끝  []  문자클래스  ()  그룹
# {n,m}  반복횟수  |  OR  (?:)  비캡처그룹
Chapter 03

C언어 — GCC로 배우는 C 기초

Linux Mint 22.3 XFCE에서 GCC로 컴파일하고 실행하는 전체 흐름부터 동적 메모리, 파일 I/O까지 다룹니다.

3-1

GCC 설치 & Hello World

C는 컴파일 언어입니다. 소스코드를 기계어로 번역하는 GCC가 필요합니다.

🐍 Python 방식
# hello.py
print("Hello!")
# $ python3 hello.py
# 바로 실행됨
⚡ C 방식
/* hello.c */
#include <stdio.h>
int main(void) {
    printf("Hello!\n");
    return 0;
}
bash — GCC 설치 & 컴파일
$ sudo apt install build-essential
$ gcc --version
gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0

# 컴파일 & 실행
$ gcc hello.c -o hello     # -o : 출력 파일명
$ ./hello
Hello!

# 권장 옵션으로 컴파일
$ gcc -Wall -Wextra -std=c11 -g hello.c -o hello
# -Wall   모든 경고 표시
# -Wextra 추가 경고
# -std=c11 C11 표준
# -g      디버그 정보 (gdb 사용 시)
# -O2     최적화 레벨 2 (배포용)

# 컴파일 에러 메시지 읽기
hello.c:4:5: error: implicit declaration of function 'prntf'
         파일:줄:열: 에러/경고 내용
gcc 컴파일 시 모든 경고를 표시하는 옵션은?
3-2

🔄컴파일 4단계 이해

hello.c 소스코드 (사람이 작성)1. 전처리(Preprocessor): #include, #define 처리 hello.i 전처리된 소스 (~800줄)2. 컴파일(Compiler): C → 어셈블리 언어 hello.s 어셈블리 코드 (mov, push, call...)3. 어셈블(Assembler): 어셈블리 → 기계어 hello.o 오브젝트 파일 (바이너리, 미완성)4. 링크(Linker): 라이브러리/오브젝트 연결 hello 실행 파일 ✓
bash — 단계별 컴파일
$ gcc -E hello.c -o hello.i   # 전처리만
$ wc -l hello.i
849 hello.i                    # stdio.h 포함 후 849줄!
$ gcc -S hello.c -o hello.s   # 어셈블리 생성
$ gcc -c hello.c -o hello.o   # 오브젝트 파일
$ gcc hello.o -o hello        # 링크

# 여러 파일 컴파일
$ gcc main.c utils.c math.c -o myapp -lm
# -lm : math 라이브러리 링크 (sin, cos, sqrt 사용 시)
3-3

📊변수 & 자료형 & 연산자

c — types.c
#include <stdio.h>
#include <stdbool.h>   // bool (C99+)
#include <stdint.h>   // int32_t 등 고정 크기

int main(void) {
    // 정수형
    char   c  = 'A';           // 1바이트
    int    i  = 2147483647;    // 4바이트
    long   l  = 9999999999L;   // 8바이트
    unsigned int u = 4294967295U;

    // 고정 크기 정수 (권장)
    int32_t  a32 = 2147483647;
    uint64_t u64 = 18446744073709551615ULL;

    // 실수형
    float  f = 3.14f;               // 4바이트, 7자리
    double d = 3.14159265358979;    // 8바이트, 15자리 (권장)

    // bool (stdbool.h)
    bool active = true, done = false;

    // 문자열 = char 배열 + \0
    char name[] = "Linux Mint";    // 11바이트 (10글자 + \0)
    char buf[64];                  // 64바이트 버퍼

    // printf 포맷
    printf("int:    %d\n", i);
    printf("double: %.4f\n", d);
    printf("char:   %c\n", c);
    printf("string: %s\n", name);
    printf("hex:    %x\n", i);
    printf("bool:   %s\n", active ? "true" : "false");
    printf("sizeof(int)=%zu sizeof(double)=%zu\n",
           sizeof(int), sizeof(double));

    // 연산자
    int x=10, y=3;
    printf("%d/%d=%d (정수)\n", x, y, x/y);      // 3
    printf("%.2f (실수)\n", (double)x/y);       // 3.33
    printf("%d%%3=%d\n", x, x%y);              // 1

    // 비트 연산 (시스템 프로그래밍 핵심)
    printf("AND:%d OR:%d XOR:%d SHL:%d\n",
           0b1010&0b1100, 0b1010|0b1100,
           0b1010^0b1100, 1<<3);    // 8 14 6 8

    return 0;
}
3-4

🔀조건문 & 반복문

c — control.c
#include <stdio.h>

int main(void) {
    // if / else if / else
    int score = 85;
    if      (score >= 90) printf("A\n");
    else if (score >= 80) printf("B\n");  // 출력됨
    else if (score >= 70) printf("C\n");
    else                  printf("F\n");

    // 삼항 연산자
    const char *grade = (score >= 60) ? "합격" : "불합격";

    // switch (정수/char만 가능, break 필수!)
    char op = '+';
    switch (op) {
        case '+': printf("더하기\n"); break;
        case '-': printf("빼기\n");   break;
        default:  printf("기타\n");
    }

    // for (초기화; 조건; 증감)
    for (int i = 0; i < 5; i++)
        printf("%d ", i);   // 0 1 2 3 4
    printf("\n");

    // 역순 for
    for (int i = 10; i >= 0; i -= 2)
        printf("%d ", i);   // 10 8 6 4 2 0

    // while
    int n = 1;
    while (n <= 100) n *= 2;   // 128

    // do-while (최소 1회 실행)
    int input;
    do {
        printf("1-10 입력: ");
        scanf("%d", &input);
    } while (input < 1 || input > 10);

    // break / continue
    for (int i = 0; i < 20; i++) {
        if (i % 2 == 0) continue;  // 짝수 건너뜀
        if (i > 10)    break;      // 10 초과 중단
        printf("%d ", i);            // 1 3 5 7 9
    }

    return 0;
}
3-5

🔧함수 & 배열

c — functions.c
#include <stdio.h>

// 함수 선언 (프로토타입) — main 위에!
int    add(int a, int b);
double average(int arr[], int size);
void   print_array(int arr[], int size);
void   bubble_sort(int arr[], int size);

int main(void) {
    printf("3+5=%d\n", add(3, 5));

    int scores[] = {85, 92, 78, 96, 88};
    int size = sizeof(scores) / sizeof(scores[0]);

    print_array(scores, size);
    printf("평균: %.1f\n", average(scores, size));
    bubble_sort(scores, size);
    print_array(scores, size);   // 정렬 후

    // 2차원 배열
    int matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
    for (int i=0; i<3; i++) {
        for (int j=0; j<3; j++)
            printf("%3d", matrix[i][j]);
        printf("\n");
    }
    return 0;
}

int add(int a, int b) { return a + b; }

double average(int arr[], int size) {
    int sum = 0;
    for (int i=0; ireturn (double)sum / size;
}

void print_array(int arr[], int size) {
    printf("[");
    for (int i=0; iprintf("%d%s", arr[i], i1?",":"");
    printf("]\n");
}

void bubble_sort(int arr[], int size) {
    for (int i=0; i1; i++)
        for (int j=0; j1; j++)
            if (arr[j] > arr[j+1]) {
                int t=arr[j]; arr[j]=arr[j+1]; arr[j+1]=t;
            }
}
3-6

👆포인터 기초

포인터는 C의 가장 강력한 기능입니다. 변수의 메모리 주소를 저장하는 변수입니다.

c — pointer.c
#include <stdio.h>

void swap(int *a, int *b);
int  sum_array(const int *arr, int size);

int main(void) {
    int  x = 10;
    int *p = &x;     // p는 x의 주소를 저장

    printf("x의 값:     %d\n", x);
    printf("x의 주소:   %p\n", (void*)&x);
    printf("p의 값:     %p\n", (void*)p);   // 같은 주소
    printf("*p (역참조): %d\n", *p);         // 10

    *p = 99;   // 포인터로 값 변경
    printf("변경 후 x: %d\n", x);  // 99

    // 배열과 포인터의 관계
    int  arr[] = {10, 20, 30, 40};
    int *q     = arr;   // 배열명 = 첫 원소 주소

    printf("%d %d %d %d\n", *q, *(q+1), *(q+2), *(q+3));
    printf("%d %d %d %d\n", q[0], q[1], q[2], q[3]);  // 동일

    // swap: 포인터 없이는 불가능!
    int a=5, b=10;
    printf("전: a=%d b=%d\n", a, b);
    swap(&a, &b);
    printf("후: a=%d b=%d\n", a, b);  // a=10 b=5

    // const 포인터: 내용 변경 불가
    const int arr2[] = {1,2,3};
    printf("sum=%d\n", sum_array(arr2, 3));

    return 0;
}

void swap(int *a, int *b) {
    int temp = *a; *a = *b; *b = temp;
}

int sum_array(const int *arr, int size) {
    int sum = 0;
    for (int i=0; ireturn sum;
}
ℹ️
포인터 핵심: &변수 → 주소 얻기 / *포인터 → 주소의 값(역참조) / int *p → p는 int를 가리키는 포인터 / 배열명은 곧 첫 원소의 주소
int x = 42; 일 때, x의 주소를 저장하는 포인터 선언과 초기화는?
3-7

🏗️구조체 (struct)

여러 자료형을 묶어 하나의 새로운 타입을 만듭니다. 파이썬의 dataclass와 유사합니다.

c — struct.c
#include <stdio.h>
#include <string.h>

// 구조체 정의 + typedef
typedef struct {
    char  name[50];
    int   age;
    float gpa;
} Student;

typedef struct {
    double x, y;
} Point;

double distance(Point a, Point b);
void   print_student(const Student *s);

int main(void) {
    // 초기화 방법 1: 선언과 동시에
    Student s1 = {"홍길동", 20, 3.8f};

    // 초기화 방법 2: 지정 초기화 (C99+)
    Student s2 = {.name="김철수", .age=22, .gpa=4.0f};

    // 멤버 접근 (. 연산자)
    printf("%s: %d살, GPA %.1f\n", s1.name, s1.age, s1.gpa);

    // 포인터로 접근 (-> 연산자)
    Student *ps = &s2;
    printf("%s: %d살\n", ps->name, ps->age);

    // 구조체 배열
    Student class_a[] = {
        {"Alice", 20, 3.9f},
        {"Bob",   21, 3.5f},
        {"Carol", 19, 4.0f},
    };
    int n = sizeof(class_a) / sizeof(class_a[0]);
    for (int i=0; iprint_student(&class_a[i]);

    // 중첩 구조체
    Point p1 = {0.0, 0.0}, p2 = {3.0, 4.0};
    printf("거리: %.2f\n", distance(p1, p2));  // 5.00
    return 0;
}

void print_student(const Student *s) {
    printf("%-10s %2d살 GPA:%.1f\n", s->name, s->age, s->gpa);
}

#include <math.h>
double distance(Point a, Point b) {
    return sqrt((b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y));
}
// 컴파일: gcc struct.c -o struct -lm
3-8

🧠동적 메모리 (malloc / free)

런타임에 필요한 만큼 메모리를 할당하고 해제합니다. 힙(Heap) 메모리를 직접 관리합니다.

c — dynamic.c
#include <stdio.h>
#include <stdlib.h>   // malloc, calloc, realloc, free
#include <string.h>   // memset, memcpy

int main(void) {
    int n;
    printf("배열 크기: ");
    scanf("%d", &n);

    // malloc: 초기화 없이 n*4바이트 할당
    int *arr = (int *)malloc(n * sizeof(int));
    if (!arr) {  // 실패 시 NULL 반환
        fprintf(stderr, "메모리 할당 실패\n");
        return 1;
    }

    // calloc: 0으로 초기화하며 할당
    int *zeros = (int *)calloc(n, sizeof(int));

    for (int i=0; i1) * 10;

    printf("원본: ");
    for (int i=0; iprintf("%d ", arr[i]);
    printf("\n");

    // realloc: 크기 변경
    int new_n = n * 2;
    int *tmp = (int *)realloc(arr, new_n * sizeof(int));
    if (!tmp) { free(arr); return 1; }
    arr = tmp;
    for (int i=n; i0;

    // 동적 구조체
    typedef struct { int id; char name[50]; } Node;
    Node *node = (Node *)malloc(sizeof(Node));
    node->id = 1;
    snprintf(node->name, 50, "홍길동");
    printf("Node: %d %s\n", node->id, node->name);

    // 반드시 해제! (메모리 누수 방지)
    free(arr);
    free(zeros);
    free(node);
    arr = zeros = node = NULL;  // 댕글링 포인터 방지

    return 0;
}
⚠️
메모리 누수(Memory Leak): malloc으로 할당한 메모리를 free하지 않으면 프로그램이 종료될 때까지 메모리를 차지합니다. valgrind --leak-check=full ./myapp으로 누수를 확인할 수 있습니다 (sudo apt install valgrind).
3-9

📁파일 입출력 (FILE*)

c — fileio.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // ── 텍스트 파일 쓰기 ─────────────────
    FILE *fp = fopen("data.txt", "w");  // w: 쓰기, r: 읽기, a: 추가
    if (!fp) { perror("fopen"); return 1; }

    fprintf(fp, "이름,나이,점수\n");
    fprintf(fp, "홍길동,25,92.5\n");
    fprintf(fp, "김철수,22,88.0\n");
    fclose(fp);

    // ── 텍스트 파일 읽기 (줄 단위) ───────
    fp = fopen("data.txt", "r");
    if (!fp) { perror("fopen"); return 1; }

    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        line[strcspn(line, "\n")] = '\0';  // \n 제거
        printf("줄: %s\n", line);
    }
    fclose(fp);

    // ── 파일 크기 확인 ───────────────────
    fp = fopen("data.txt", "r");
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    rewind(fp);
    printf("파일 크기: %ld바이트\n", size);

    // ── 파일 전체 읽기 (동적 할당) ───────
    char *content = (char*)malloc(size + 1);
    fread(content, 1, size, fp);
    content[size] = '\0';
    printf("내용:\n%s\n", content);

    free(content);
    fclose(fp);

    // 파일 모드
    // "r"  읽기 (파일 없으면 NULL)
    // "w"  쓰기 (없으면 생성, 있으면 초기화)
    // "a"  추가 (없으면 생성)
    // "r+" 읽기+쓰기
    // "rb" 바이너리 읽기

    return 0;
}
#include <string.h>
3-10

📚표준 라이브러리 활용

c — stdlib_demo.c
#include <stdio.h>
#include <stdlib.h>    // atoi, atof, rand, qsort, abs
#include <string.h>    // strlen, strcpy, strcat, strcmp, strstr
#include <math.h>      // sqrt, pow, sin, cos, floor, ceil
#include <time.h>      // time, clock
#include <ctype.h>     // isdigit, isalpha, toupper, tolower

int cmp_int(const void *a, const void *b);  // qsort용

int main(void) {
    // ── string.h ────────────────────────
    char s1[50] = "Hello";
    char s2[]   = " Linux";

    printf("길이: %zu\n", strlen(s1));         // 5
    strcat(s1, s2);
    printf("합치기: %s\n", s1);               // Hello Linux
    printf("비교: %d\n", strcmp("a", "b"));  // 음수 (a
    printf("검색: %s\n", strstr(s1, "Linux")); // Linux

    // ── math.h ──────────────────────────
    printf("sqrt(16)=%.1f\n", sqrt(16.0));  // 4.0
    printf("pow(2,8)=%.0f\n", pow(2.0, 8.0)); // 256
    printf("ceil(3.2)=%.0f\n", ceil(3.2));  // 4
    printf("floor(3.9)=%.0f\n", floor(3.9)); // 3

    // ── stdlib.h ────────────────────────
    printf("atoi: %d\n", atoi("42"));         // 42
    printf("atof: %.2f\n", atof("3.14"));    // 3.14
    printf("abs: %d\n", abs(-15));          // 15

    // rand & srand (난수)
    srand(time(NULL));
    for (int i=0; i<5; i++)
        printf("%d ", rand() % 100);   // 0~99 난수

    // qsort (범용 정렬)
    int arr[] = {5,2,8,1,9,3};
    qsort(arr, 6, sizeof(int), cmp_int);
    for (int i=0; i<6; i++) printf("%d ", arr[i]);

    // ── ctype.h ─────────────────────────
    char ch = 'a';
    printf("\n%c→%c\n", ch, toupper(ch));  // a→A
    printf("isdigit('5')=%d\n", isdigit('5'));   // 非0

    return 0;
}

int cmp_int(const void *a, const void *b) {
    return (*(int*)a) - (*(int*)b);
}
// 컴파일: gcc stdlib_demo.c -o stdlib_demo -lm
3-11

🔧전처리기 (#define / #ifdef)

c — preprocessor.c
#include <stdio.h>

// ── 상수 정의 ────────────────────────────────
#define MAX_SIZE    100
#define PI          3.14159265
#define APP_NAME    "LinuxLab"
#define VERSION     "1.0.0"

// ── 함수형 매크로 ────────────────────────────
#define SQUARE(x)   ((x) * (x))    // 괄호 중요!
#define MAX(a,b)    ((a)>(b) ? (a) : (b))
#define MIN(a,b)    ((a)<(b) ? (a) : (b))
#define ABS(x)      ((x)>=0 ? (x) : -(x))
#define SWAP(t,a,b) do{t _t=a; a=b; b=_t;}while(0)

// ── 헤더 가드 (헤더파일에서 이중 포함 방지) ──
#ifndef MYLIB_H
#define MYLIB_H
/* 헤더 내용 */
#endif

// ── 조건부 컴파일 ────────────────────────────
#define DEBUG  // 이 줄을 주석처리하면 디버그 비활성화

#ifdef DEBUG
  #define LOG(msg) printf("[DEBUG] %s:%d: %s\n", __FILE__, __LINE__, msg)
#else
  #define LOG(msg)  // 비어있음 → 릴리즈 빌드에서 사라짐
#endif

#ifdef __linux__
  #define PLATFORM "Linux"
#elif defined(_WIN32)
  #define PLATFORM "Windows"
#else
  #define PLATFORM "Unknown"
#endif

int main(void) {
    printf("%s v%s\n", APP_NAME, VERSION);
    printf("플랫폼: %s\n", PLATFORM);
    printf("SQUARE(5)=%d\n", SQUARE(5));  // 25
    printf("MAX(3,7)=%d\n",  MAX(3, 7));  // 7

    LOG("프로그램 시작");

    int arr[MAX_SIZE];
    for (int i=0; i// gcc로 외부에서 #define 하기
    // gcc -DDEBUG -DMAX_SIZE=200 main.c -o main

    return 0;
}
C에서 헤더 파일의 이중 포함을 방지하는 패턴(헤더 가드)에 사용하는 전처리기 지시어는?
3-12

🗂️Makefile 기초

여러 파일 프로젝트의 빌드를 자동화합니다. 변경된 파일만 재컴파일해 효율적입니다.

makefile — Makefile (들여쓰기는 Tab!)
# 변수 정의
CC      = gcc
CFLAGS  = -Wall -Wextra -std=c11 -g
LDFLAGS = -lm
TARGET  = myapp
SRCS    = main.c utils.c math_utils.c
OBJS    = $(SRCS:.c=.o)          # .c → .o 치환
HEADERS = utils.h math_utils.h

# 기본 타겟
all: $(TARGET)

# 실행파일 빌드
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
	@echo "✓ 빌드 완료: $(TARGET)"

# 오브젝트 파일 빌드 (패턴 규칙)
%.o: %.c $(HEADERS)
	$(CC) $(CFLAGS) -c $< -o $@

# 정리
clean:
	rm -f $(OBJS) $(TARGET)
	@echo "정리 완료"

# 빌드 후 실행
run: $(TARGET)
	./$(TARGET)

# 디버그 빌드
debug: CFLAGS += -DDEBUG -O0
debug: $(TARGET)

# 릴리즈 빌드
release: CFLAGS := -Wall -O2 -std=c11
release: $(TARGET)

# 가짜 타겟 선언
.PHONY: all clean run debug release
bash — make 사용
$ make           # 빌드
gcc -Wall -Wextra -std=c11 -g -c main.c -o main.o
gcc -Wall -Wextra -std=c11 -g -c utils.c -o utils.o
gcc -Wall -Wextra -std=c11 -g -o myapp main.o utils.o -lm
✓ 빌드 완료: myapp

$ make           # 변경 없으면
make: 'myapp' is up to date.

$ make run       # 실행
$ make clean     # 정리
$ make debug     # 디버그 빌드
$ make -j4       # 4코어 병렬 빌드
💡
Makefile 핵심 규칙: (1) 들여쓰기는 반드시 Tab (스페이스 불가!) (2) $@ = 타겟명, $^ = 모든 의존성, $< = 첫 번째 의존성 (3) @로 시작하는 명령은 출력 안 됨