Day 1에서 우리는 "모든 것은 파일이다"라는 유닉스 철학을 만났다. 오늘은 그 철학이 실제 리눅스 안에서 어떻게 구현되는지를 두 측면에서 깊이 파고든다. 첫째는 공간적 구조다. 리눅스의 모든 파일은 단 하나의 루트(/)에서 시작하는 거대한 나무에 매달려 있고, 그 가지들이 어디에 무엇을 담는지는 FHS라는 표준으로 약속되어 있다. 둘째는 파일의 종류다. 우리가 흔히 떠올리는 텍스트 파일·디렉터리뿐 아니라, 장치를 표현하는 파일, 프로세스 간 통신용 파일, 다른 파일을 가리키는 링크까지 모두 "파일"로 다뤄진다. 특히 하드링크와 심볼릭링크의 차이는 1급 시험과 실기에서 거의 빠지지 않는 핵심이다. 오늘은 inode라는 파일시스템의 근본 개념까지 함께 다룬다.
리눅스를 처음 보면 /bin, /etc, /var 같은 디렉터리가 낯설다. 이 배치는 무작위가 아니라 **FHS(Filesystem Hierarchy Standard, 파일시스템 계층 표준)**라는 공식 규약을 따른다. FHS 덕분에 어떤 배포판을 쓰든 "설정 파일은 /etc에, 로그는 /var/log에 있다"는 약속이 지켜진다. 이 표준이 없다면 배포판마다 파일 위치가 제각각이라 관리가 불가능했을 것이다.
리눅스 파일시스템은 윈도우와 근본적으로 다르다. 윈도우는 드라이브마다 C:, D:처럼 별도의 루트가 있지만, 리눅스는 **단 하나의 루트(/)**에서 모든 것이 뻗어나가는 단일 계층 트리다. 다른 디스크나 USB는 이 트리의 특정 디렉터리에 "마운트(mount)"되어 가지로 합쳐진다.
주요 디렉터리와 그 역할을 정리하면 다음과 같다.
| 디렉터리 | 역할 | 핵심 내용 |
|---|---|---|
/ | 루트 | 전체 트리의 시작점 |
/bin | 필수 명령어 | ls, cp, cat 등 모든 사용자용 기본 명령 |
/sbin | 시스템 명령어 | fdisk, ip 등 관리자용 명령 |
/etc | 설정 파일 | passwd, fstab 등 시스템 전역 설정 |
/home | 사용자 홈 | 일반 사용자의 개인 디렉터리 |
/root | 관리자 홈 | root 계정의 홈 디렉터리 |
/var | 가변 데이터 | 로그(/var/log), 메일, 캐시 |
/tmp | 임시 파일 | 재부팅 시 삭제될 수 있는 임시 공간 |
/usr | 사용자 프로그램 | 추가 설치된 응용 프로그램(/usr/bin) |
/dev | 장치 파일 | 디스크·터미널 등 하드웨어 표현 |
/proc | 프로세스 정보 | 가상 파일시스템, 커널/프로세스 상태 |
/sys | 시스템 정보 | 가상 파일시스템, 하드웨어/드라이버 정보 |
/lib | 공유 라이브러리 | /bin, /sbin이 쓰는 라이브러리 |
/boot | 부팅 파일 | 커널(vmlinuz), initramfs, GRUB |
/mnt, /media | 마운트 지점 | 임시 마운트(/mnt), 자동 마운트(/media) |
/opt | 선택 패키지 |
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
`ls -l` 명령 결과의 맨 앞 식별 문자와 파일 종류의 연결이 옳지 않은 것은?
문제 2
하드링크와 심볼릭링크의 차이에 대한 설명으로 옳은 것은?
문제 3
리눅스 파일시스템에서 inode에 저장되지 않는 정보는?
문제 4
FHS(Filesystem Hierarchy Standard)에 따른 디렉터리 역할로 옳지 않은 것은?
문제 5
`/proc`와 `/sys` 디렉터리에 대한 설명으로 옳은 것은?
문제 6
다음 명령을 순서대로 실행했을 때 마지막 `cat soft.txt`의 결과로 옳은 것은? ``` echo "data" > orig.txt ln orig.txt hard.txt ln -s orig.txt soft.txt rm orig.txt ```
| 서드파티 대형 응용 프로그램 |
💡 개념:
/bin과/sbin의 차이를 기억하자./bin은 모든 사용자가 쓰는 일반 명령(ls, cp),/sbin은 주로 관리자(root)가 쓰는 시스템 관리 명령(fdisk, reboot)이다. "s"는 system 또는 superuser를 뜻한다. 마찬가지로/usr/bin,/usr/sbin도 같은 구분을 따른다. 최근 배포판은/bin을/usr/bin의 심볼릭링크로 통합(usrmerge)하는 추세다.
FHS의 디렉터리 중 /proc와 /sys는 특별하다. 이들은 디스크에 실제로 존재하는 파일이 아니라, 커널이 메모리상에서 실시간으로 만들어내는 **가상 파일시스템(virtual filesystem)**이다. "모든 것은 파일"이라는 철학이 가장 극적으로 드러나는 곳이다. 프로세스 정보, CPU 정보, 메모리 사용량 같은 커널 내부 상태를 파일을 읽듯이 확인할 수 있다.
# /proc - 커널과 프로세스 정보를 파일처럼 읽기
cat /proc/cpuinfo # CPU 상세 정보
cat /proc/meminfo # 메모리 사용 현황
cat /proc/version # 커널 버전
ls /proc/1/ # PID 1번 프로세스의 정보 디렉터리
# /sys - 하드웨어와 드라이버 정보
cat /sys/class/net/eth0/address # 네트워크 인터페이스 MAC 주소
# 직접 쳐보기: 자신의 CPU 코어 수를 파일에서 세어보기
grep -c processor /proc/cpuinfo🔍 더 깊이:
/proc의 각 숫자 디렉터리(/proc/1234)는 PID 1234 프로세스에 대응한다. 그 안의status,cmdline,fd/를 읽으면 그 프로세스가 어떤 명령으로 실행됐고 어떤 파일을 열고 있는지 알 수 있다.top,ps같은 도구들도 사실 내부적으로/proc를 읽어 정보를 보여주는 것이다. 가상 파일시스템은 0바이트 크기로 보이지만 읽으면 실시간 데이터가 나온다.
리눅스에서 "파일"은 단순한 데이터 묶음 그 이상이다. ls -l 명령의 맨 앞 글자 하나가 그 파일의 종류를 알려준다. 이 식별 문자는 1급 시험의 단골 출제 포인트다.
| 식별자 | 종류 | 설명 |
|---|---|---|
- | 일반 파일(regular) | 텍스트, 실행 바이너리, 이미지 등 |
d | 디렉터리(directory) | 다른 파일들을 담는 폴더 |
l | 심볼릭 링크(symbolic link) | 다른 파일을 가리키는 바로가기 |
b | 블록 장치(block device) | 디스크처럼 블록 단위 I/O (예: /dev/sda) |
c | 문자 장치(character device) | 키보드처럼 문자 단위 I/O (예: /dev/tty) |
s | 소켓(socket) | 프로세스 간 양방향 통신 |
p | 파이프(named pipe, FIFO) | 프로세스 간 단방향 통신 |
# ls -l의 첫 글자로 파일 종류 확인
ls -l /dev/sda # b로 시작 → 블록 장치
ls -l /dev/tty # c로 시작 → 문자 장치
ls -l /etc/passwd # -로 시작 → 일반 파일
ls -ld /etc # d로 시작 → 디렉터리
# file 명령으로 내용 기반 파일 종류 판별
file /etc/passwd # ASCII text
file /bin/ls # ELF 실행 바이너리블록 장치와 문자 장치의 차이는 중요하다. 블록 장치(b)는 데이터를 정해진 크기의 블록 단위로 읽고 쓰며 버퍼링과 임의 접근이 가능하다. 디스크, SSD, USB가 여기 속한다. 문자 장치(c)는 데이터를 한 글자씩 순차적으로 흘려보낸다. 키보드, 마우스, 시리얼 포트, 터미널이 여기 속한다.
**소켓(s)과 파이프(p)**는 프로세스 간 통신(IPC) 수단이다. 파이프(FIFO, named pipe)는 한 방향으로만 데이터가 흐르고, 소켓은 양방향 통신이 가능하며 네트워크 통신에도 쓰인다.
⚠️ 함정: 시험에서 "디스크 /dev/sda는 어떤 종류의 장치 파일인가?"라고 물으면 답은 **블록 장치(b)**다. "키보드나 터미널은?"이라고 물으면 **문자 장치(c)**다. 블록(랜덤 접근, 버퍼링)과 문자(순차, 스트림)의 구분을 헷갈리지 말자.
/dev/sda의 's'는 SCSI/SATA를 뜻하지 socket의 's'가 아니다.
링크를 이해하려면 먼저 inode(아이노드, index node)를 알아야 한다. 이것이 리눅스 파일시스템의 가장 근본적인 개념이다.
우리는 흔히 "파일 = 이름 + 내용"이라고 생각하지만, 리눅스에서 파일의 본질은 inode다. inode는 파일에 대한 모든 메타데이터를 담은 자료구조로, 다음을 포함한다.
여기서 핵심은, 파일 이름은 inode에 포함되지 않는다는 점이다. 파일 이름은 디렉터리 안에 "이름 → inode 번호" 매핑으로 저장될 뿐이다. 즉 디렉터리는 사실 "이름과 inode 번호의 짝을 담은 표"다.
# inode 번호 확인
ls -i file.txt # 파일의 inode 번호 표시
stat file.txt # inode 번호, 크기, 권한, 타임스탬프 등 상세
df -i # 파일시스템별 inode 사용량💡 개념: 파일시스템을 만들 때 inode 개수가 정해진다. 디스크 용량이 남아도 inode가 고갈되면 더 이상 파일을 만들 수 없다(
df -i로 확인). 작은 파일을 무수히 만드는 메일 서버 등에서 "용량은 남았는데 No space left on device" 오류가 나는 것이 바로 inode 고갈 때문이다. 이것이 inode가 실무에서 중요한 이유다.
이제 inode를 이해했으니, 두 종류의 링크를 명확히 구분할 수 있다. 이것은 1급 시험에서 거의 매번 출제되는 최중요 주제다.
**하드링크(hard link)**는 같은 inode를 가리키는 또 다른 이름이다. 새 inode를 만들지 않고, 기존 inode를 가리키는 이름(디렉터리 엔트리)만 하나 더 추가한다. 따라서 원본과 하드링크는 inode 번호가 완전히 같고, 사실상 동등한 존재다. 둘 중 어느 것이 "원본"인지 구분할 수 없다. inode의 링크 수가 1 증가하며, 모든 이름을 지워 링크 수가 0이 되어야 실제 데이터가 삭제된다.
**심볼릭링크(symbolic link, soft link)**는 다른 파일의 경로(이름)를 담고 있는 별도의 파일이다. 윈도우의 "바로가기"와 같다. 자기만의 새 inode를 가지며, 그 안에 "내가 가리키는 대상의 경로"가 문자열로 저장되어 있다. 원본을 찾아갈 때는 그 경로를 따라간다.
| 항목 | 하드링크 | 심볼릭링크 |
|---|---|---|
| inode | 원본과 동일 | 자신만의 새 inode |
| 가리키는 대상 | inode(데이터) 직접 | 경로(이름) 문자열 |
| 원본 삭제 시 | 데이터 유지(링크 수만 감소) | 깨진 링크(dangling)가 됨 |
| 다른 파일시스템 | 불가능 | 가능 |
| 디렉터리 대상 | 불가능(일반적으로) | 가능 |
| 크기 | 원본과 같음 | 대상 경로 문자열 길이 |
# 하드링크 생성 (ln, 옵션 없음)
ln original.txt hardlink.txt
ls -li original.txt hardlink.txt # inode 번호가 동일함을 확인
# 심볼릭링크 생성 (ln -s)
ln -s original.txt symlink.txt
ls -li original.txt symlink.txt # inode 번호가 다름, l로 표시
# 직접 쳐보기: 원본을 지운 뒤 차이를 관찰
echo "hello" > orig.txt
ln orig.txt hard.txt
ln -s orig.txt soft.txt
rm orig.txt
cat hard.txt # 정상 출력 (데이터 유지)
cat soft.txt # No such file (깨진 링크)위 실습이 두 링크의 본질적 차이를 가장 잘 보여준다. 원본 orig.txt를 삭제하면, 하드링크 hard.txt는 같은 inode를 직접 가리키므로 데이터가 그대로 살아있다(inode의 링크 수가 2→1로 줄었을 뿐). 반면 심볼릭링크 soft.txt는 "orig.txt라는 경로"를 저장하고 있는데 그 경로가 사라졌으므로 깨진 링크가 된다.
⚠️ 함정: "심볼릭링크는 다른 파일시스템(파티션)과 디렉터리를 가리킬 수 있지만, 하드링크는 둘 다 불가능하다"가 핵심 출제 포인트다. 이유는 명확하다. 하드링크는 inode 번호를 공유하는데, inode 번호는 각 파일시스템 안에서만 유일하므로 파티션을 넘을 수 없다. 디렉터리 하드링크를 금지하는 이유는 파일시스템 트리에 순환(loop)이 생겨
find같은 도구가 무한 반복에 빠지는 것을 막기 위함이다.
🔍 더 깊이:
ls -l로 디렉터리를 보면 권한 옆에 숫자가 있다(예:drwxr-xr-x 2). 이 숫자가 바로 inode의 링크 수다. 새 디렉터리를 만들면 링크 수가 기본 2다. 자기 자신을 가리키는.과 부모가 자식을 가리키는 이름, 이렇게 2개의 하드링크가 자동 생성되기 때문이다. 하위 디렉터리를 하나 만들 때마다 그 안의..이 부모를 가리키므로 부모의 링크 수가 1씩 늘어난다.
📚 유래/사례: "inode"라는 이름의 유래는 데니스 리치도 정확히 기억하지 못한다고 밝힌 바 있다. 가장 유력한 설은 "index node"의 줄임말로, 파일의 정보를 색인(index)하는 노드라는 의미다. 1970년대 초 유닉스 초기 파일시스템 설계에서 탄생한 이 개념은 50년이 지난 지금도 ext4, XFS 등 리눅스 파일시스템의 근간으로 살아있다.
파일시스템 트리를 탐색하려면 경로를 표현하는 두 방식을 알아야 한다.
**절대경로(absolute path)**는 루트(/)에서 시작하는 완전한 경로다. 항상 /로 시작하며, 현재 위치와 무관하게 동일한 파일을 가리킨다. 예: /home/user/docs/file.txt.
**상대경로(relative path)**는 현재 작업 디렉터리(pwd)를 기준으로 한 경로다. /로 시작하지 않는다. 특수 기호로 .(현재 디렉터리), ..(부모 디렉터리), ~(홈 디렉터리)를 쓴다.
pwd # 현재 작업 디렉터리(절대경로) 확인
cd /etc # 절대경로로 이동
cd ../var # 상대경로: 부모로 올라간 뒤 var로
cd ~ # 홈 디렉터리로
cd - # 직전 디렉터리로 토글💡 개념:
.과..은 단순한 기호가 아니라 모든 디렉터리에 실제로 존재하는 하드링크다.ls -a로 보면 어떤 디렉터리에든.(자기 자신)과..(부모)가 보인다. 이것이 디렉터리의 기본 링크 수가 2인 이유와 연결된다.
오늘은 "모든 것은 파일"이라는 철학의 구체적 실현을 두 축으로 살펴봤다. 공간적으로 리눅스는 단일 루트(/)에서 뻗는 FHS 표준 트리이며, /etc(설정)·/var(로그)·/dev(장치)·/proc(가상) 등 각 디렉터리의 역할이 약속되어 있다. 파일의 종류는 ls -l의 첫 글자로 구분되며 일반(-)·디렉터리(d)·심볼릭링크(l)·블록장치(b)·문자장치(c)·소켓(s)·파이프(p)의 7가지다. 그리고 파일의 진짜 정체는 이름이 아니라 inode이며, 이 inode 개념이 하드링크(같은 inode 공유)와 심볼릭링크(경로를 담은 새 inode)의 차이를 결정한다. 다음 시간에는 이번 주에 배운 운영체제 개념·라이선스·부팅·파일시스템을 종합 복습하고, 시험 유형의 문제로 실력을 점검한다.