문서 읽는 데 54분 · A2

A-2: 파일과 디렉토리 다루기

목차 29
전체 12강 중 2강 · 리눅스
난이도 · 입문

ℹ️서버·배포에서 쓰는 리눅스 셸과 명령어 기본기. 백엔드·인프라로 가기 전에 익혀두면 든든해요.

안녕하세요, 홍순구입니다. 지난 시간에 우리는 검은 창을 열고 리눅스 안을 두 발로 걸어 다녔어요. pwd로 내 위치를 확인하고, ls로 주변을 둘러보고, cd로 이리저리 옮겨 다녔죠. 이제 그 길을 제법 익숙하게 누비게 됐을 거예요.

그런데 여행자가 길만 알고 끝나면 좀 아쉽죠. 오늘은 그 위에서 직접 손을 댑니다. 빈 파일을 만들고, 폴더를 짓고, 내용을 들여다보고, 복사하고, 옮기고, 이름을 바꾸고, 그리고 — 조심스럽게 — 지워봅니다. 리눅스를 "걸어 다니는" 단계에서 "내 손으로 다듬는" 단계로 넘어가는 거예요.

오늘 다룰 소재는 현업에서 정말 자주 만나는 상황이에요. 서버 한구석에 로그 파일이 잔뜩 어질러져 있다고 상상해보세요. 어떤 건 오래돼서 지워도 되고, 어떤 건 백업해둬야 하고, 어떤 건 묶어서 압축해 보관해야 하죠. 오늘 배우는 명령들이 바로 그 "정리"를 해내는 도구입니다. 그래서 우리도 연습용 로그 파일 몇 개를 만들어두고, 그걸 보고·옮기고·찾고·압축하며 하나씩 익혀 나갈 거예요.

한 가지 미리 안심시켜 드릴게요. 오늘 "지우기"도 배우는데, 리눅스에는 윈도우 같은 휴지통이 없어서 한 번 지운 파일은 되돌릴 수 없어요. 무섭게 들리죠? 그런데 괜찮아요. 겁먹을 일이 아니라 습관의 문제거든요. "치기 전에 ls로 한 번 확인하고, 중요한 건 미리 복사해두고, rm -i로 한 번 더 물어보게 한다" — 이 세 가지만 몸에 배면 실수할 일이 거의 없습니다. 오늘 그 안전한 습관까지 함께 익혀요.

오늘 우리가 걸어갈 길을 한눈에 그려둘게요.

텍스트
  [만든다]  touch·mkdir         [본다]  cat·less·head·tail·wc
       │
       
  [옮긴다·지운다]  cp·mv·rm      [골라잡는다]  와일드카드  *  ?  [ ]
       │
       
  [찾는다]  find                [묶어 압축한다]  tar·gzip·zip

명령이 좀 많아 보여도 걱정 마세요. 하나씩, 왜 필요한지부터 풀어가며 천천히 갈 테니 편하게 따라오면 됩니다.

💡 오늘 수업의 핵심 — "내 손으로 파일을 만들고, 보고, 옮기고, 안전하게 지우고, 찾아서 압축한다"

빈 파일과 폴더를 직접 만들고, 그 안을 들여다보고, 복사·이동·이름변경으로 정리하고, "휴지통이 없는" 리눅스에서 안전하게 지우는 습관을 들이고, 와일드카드로 여러 개를 한 번에 다루고, find로 찾아 tar로 묶어 압축하는 것 — 여기까지가 오늘의 목표입니다.

🎯 학습 목표

  • 파일·디렉토리를 직접 만들고(touch·mkdir), 내용을 들여다보고(cat·less·head·tail·wc), 복사·이동·이름변경(cp·mv)으로 정리한다
  • 휴지통이 없는 리눅스에서 안전하게 지우는 습관(ls 확인·백업·rm -i)을 익히고, 와일드카드(*·?·[]·{})로 여러 파일을 한 번에 다룬다
  • find로 원하는 파일을 찾아내고, tar·gzip·zip으로 묶어 압축해 깔끔하게 보관한다

Step 1: "내 손으로 첫 파일 — touch와 mkdir"

지난 시간엔 남이 만들어둔 폴더들 사이를 걸어 다녔어요. 오늘은 우리만의 연습장을 직접 지어봅니다. 먼저 홈으로 가서 practice라는 폴더를 하나 만들게요.

Bash
cd ~
mkdir practice
cd practice

mkdirmake directory, 그러니까 "폴더(디렉토리)를 만들어라"예요. 방금 빈 연습장 하나가 생겼고, cd practice로 그 안에 들어왔습니다. ls를 쳐보면 아직 텅 비어 있을 거예요. 당연하죠, 방금 만들었으니까.

이제 폴더 안에 폴더를 또 만들어볼게요. 그런데 한 번에 여러 층을 만들고 싶을 때가 있어요. 예를 들어 project 안에 logs, 그 안에 2026까지 한 줄로요.

Bash
mkdir -p project/logs/2026

여기서 -p가 핵심이에요. 그냥 mkdir project/logs/2026이라고 치면 "어? projectlogs도 아직 없는데?" 하면서 에러가 납니다. -p(parents, 부모 폴더까지)를 붙이면 중간 단계가 없어도 위에서부터 차곡차곡 다 만들어줘요. 게다가 이미 있는 폴더를 또 -p로 만들라고 해도 에러 없이 조용히 넘어갑니다. 그래서 스크립트에서 안전하게 쓰기 좋아요.

폴더를 만들었으니 이번엔 빈 파일을 만들어봅시다.

Bash
touch access.log
touch error.log debug.log

touch는 빈 파일을 만들어요. 한 번에 여러 개도 됩니다 — 위처럼 error.log debug.log 두 개를 띄어 쓰면 둘 다 생겨요. 이제 ls -l로 확인해볼게요.

Bash
ls -l
텍스트
합계 0
drwxr-xr-x 3 alice alice 4096 Jun 16 10:21 project
-rw-r--r-- 1 alice alice    0 Jun 16 10:21 access.log
-rw-r--r-- 1 alice alice    0 Jun 16 10:21 debug.log
-rw-r--r-- 1 alice alice    0 Jun 16 10:21 error.log

(alice 자리엔 여러분 계정 이름이 떠요.) 파일들 크기가 0이죠? 안에 아무것도 없는 빈 파일이라 그래요. 줄 맨 앞의 drwxr-xr-x·-rw-r--r-- 같은 글자도 보일 텐데, 이건 "권한"이라는 거예요. 오늘은 그냥 눈에 익혀만 두고, 읽고 바꾸는 법은 다음 시간에 배웁니다.

현업 서버에서도 새 서비스를 올릴 때 mkdir -p /app/logs 한 줄로 로그가 쌓일 폴더 구조를 미리 잡아두고 시작해요. 손으로 하나하나 만들 필요 없이 한 줄이면 끝나니까요.

💡 한 줄 정리

폴더는 mkdir(중첩은 -p로 한 번에), 빈 파일은 touch로 만든다. 만든 결과는 ls로 바로 확인한다.

🙋 학생 질문 — "touch는 '만지다'라는 뜻인데, 왜 파일이 만들어지나요?"

날카로운 질문이에요. 사실 touch의 원래 임무는 파일을 만드는 게 아니라, 이미 있는 파일의 "마지막으로 손댄 시각(타임스탬프)"을 지금으로 톡 갱신하는 거예요. 말 그대로 파일을 살짝 "건드리는" 거죠.

그런데 없는 파일을 건드리라고 하면, 리눅스가 "건드릴 게 없네? 그럼 빈 걸로 하나 만들어두고 건드린 셈 칠게요" 하고 빈 파일을 만들어줍니다. 우리는 그 부수효과를 "빈 파일 빠르게 만들기"로 빌려 쓰는 거예요. 그래서 파일 만들기 명령치고 이름이 좀 엉뚱한 거랍니다.


Step 2: "파일 속을 들여다보기 — cat과 less"

파일을 만들었으니 이제 안을 들여다볼 차례예요. 그런데 우리가 방금 만든 건 빈 파일이라 볼 게 없죠. 그래서 이번엔 리눅스에 원래 있는, 내용이 든 진짜 파일을 열어볼게요. 서버에서 진짜로 보게 될 건 로그 파일인데, 로그는 권한이 필요할 때가 많아서(그건 다음 시간 주제예요) 오늘은 누구나 읽을 수 있는 파일로 연습합니다.

먼저 짧은 파일부터. 내 리눅스가 어떤 배포판인지 적혀 있는 파일이에요.

Bash
cat /etc/os-release
텍스트
PRETTY_NAME="Ubuntu 26.04 LTS"
NAME="Ubuntu"
VERSION_ID="26.04"
VERSION="26.04 LTS (Resolute Raccoon)"
VERSION_CODENAME=resolute
ID=ubuntu
...

cat은 파일 내용을 화면에 통째로 쏟아내요. 이름은 concatenate(이어 붙이다)에서 왔는데, 지금은 "파일 내용을 그대로 보여주는 도구"로 기억하면 돼요. 줄 번호를 같이 보고 싶으면 cat -n을 쓰면 됩니다.

cat은 짧은 파일엔 딱이에요. 그런데 수천, 수만 줄짜리 파일에 cat을 쓰면? 화면이 폭포처럼 좌르륵 쏟아지고, 다 지나가 버려서 위쪽은 읽을 수도 없어요. 이럴 땐 less를 씁니다.

Bash
less /etc/services

/etc/services는 포트 번호와 이름이 수천 줄 적힌 긴 파일이에요. less로 열면 화면이 쏟아지는 대신 한 페이지씩 멈춰서 보여줍니다. 안에서 이렇게 움직여요.

텍스트
  less 안에서 움직이는 법
       (또는 j k)   한 줄씩 위아래로
    Space            한 페이지 아래로
    b                한 페이지 위로
    /검색어          파일 안에서 단어 찾기  (예: /ERROR)
    n                다음 검색 결과로
    G                맨 끝으로 / g  맨 처음으로
    q                빠져나오기

지난 시간에 man으로 도움말을 읽다가 q로 빠져나왔던 그 화면, 기억나죠? 그게 바로 less였어요. man은 도움말을 less에 띄워서 보여주는 거였거든요. 그래서 움직이는 법이 똑같습니다.

현업 서버에선 로그가 수만 줄일 때 cat은 위험해요. 화면만 어지럽히고 위로 못 올라가거든요. less로 열어서 /ERROR로 검색하면 에러가 난 줄로 바로 점프합니다.

💡 한 줄 정리

짧은 파일은 cat으로 통째로, 긴 파일은 less로 페이지를 넘기며 본다(/로 검색, q로 나오기).

🙋 학생 질문 — "less로 열었더니 화살표도 안 먹는 것 같고 글자도 안 쳐져요. 어떻게 빠져나오죠?"

당황하지 마세요, 아주 흔한 일이에요. less는 "읽기 전용 뷰어"라서, vim 같은 편집기처럼 글자를 입력하는 화면이 아니에요. 그래서 막 타이핑하면 이상한 반응만 나와요.

빠져나오는 건 q 한 글자면 끝이에요(지난 시간 man에서 쓰던 그 q 맞아요). 화살표가 안 먹는 것처럼 느껴지면 j를, 페이지를 넘기려면 Space를 눌러보세요. 검색은 /를 누르고 단어를 친 뒤 엔터예요. 정 헷갈리면 일단 q로 나온 다음 다시 천천히 들어가면 됩니다.


Step 3: "필요한 만큼만 — head·tail·wc"

긴 파일을 less로 넘겨보는 것도 좋지만, 때론 "맨 앞 몇 줄만" 또는 "맨 끝 몇 줄만" 슥 보고 싶을 때가 있어요. 로그는 보통 끝에 최신 기록이 쌓이니까 "마지막 몇 줄"을 자주 보거든요. 이럴 때 쓰는 게 headtail이에요.

Bash
head -n 5 /etc/services
tail -n 5 /etc/services

head는 머리(앞), tail은 꼬리(뒤)예요. -n 5는 "5줄만". 숫자를 안 붙이면 기본 10줄을 보여줍니다.

tail엔 아주 유용한 친구가 하나 있어요. -f(follow, 따라가기) 옵션이에요.

Bash
tail -f /var/log/syslog

이걸 켜두면 화면이 끝나지 않고 멈춰 있는 것처럼 보여요. 고장이 아니에요. 파일 끝에 새 줄이 추가될 때마다 실시간으로 화면에 흘려주는 중이거든요. 서버에서 방금 배포한 서비스가 잘 도는지, 에러 로그가 실시간으로 찍히는지 지켜볼 때 이만한 게 없어요. 멈추려면 Ctrl + C를 누릅니다. (실시간 로그 감시는 다음다음 시간에 파이프와 엮어 더 강력하게 다룰 거예요. 오늘은 "이런 게 있다" 정도만.)

마지막으로 wc. 파일이 몇 줄인지, 몇 단어인지 세어줘요.

Bash
wc -l /etc/services
텍스트
11473 /etc/services

wcword count인데, -l(lines)을 붙이면 줄 수만 딱 알려줘요. 옵션 없이 wc 파일이라고 치면 "줄 수 / 단어 수 / 바이트 수" 세 숫자를 한꺼번에 보여줍니다. "이 로그 파일에 기록이 몇 건이나 쌓였지?"를 한 줄로 셀 수 있어요.

이 세 명령을 한눈에 정리하면 이래요.

텍스트
  파일 한 개 (예: 11473줄)
    │
    ├─ head -n 5     맨 앞 5줄만 보기
    ├─ tail -n 5     맨 뒤 5줄만 보기
    ├─ tail -f       끝에 새로 붙는 줄을 실시간으로 따라가기 (Ctrl+C로 멈춤)
    └─ wc -l         전부 몇 줄인지 숫자 하나로

현업에선 "에러 로그 마지막 20줄만 보여줘" 할 때 tail -n 20, "방금 띄운 서버 로그 실시간으로 봐야지" 할 때 tail -f를 입에 달고 살아요.

💡 한 줄 정리

앞은 head, 뒤는 tail(실시간은 tail -f), 개수는 wc -l. 큰 파일을 통째로 열지 않고 필요한 만큼만 본다.

🙋 학생 질문 — "tail -f를 쳤더니 화면이 멈춘 채 안 끝나요. 제가 뭘 잘못한 건가요?"

잘못한 거 하나도 없어요. 그게 정상 동작이에요. -f는 "파일을 계속 따라가라"는 뜻이라, 새 줄이 붙기를 기다리며 일부러 켜진 채로 머물러 있는 거예요. 실시간 로그를 지켜볼 때 쓰는 거라 끝나지 않는 게 당연해요.

다 봤으면 Ctrl + C를 누르면 빠져나옵니다. (Ctrl + C는 "지금 켜둔 명령을 멈춰라"라는 만능 탈출 신호예요. 앞으로도 명령이 안 끝나고 멈춰 있는 것 같으면 일단 Ctrl + C를 떠올리세요.) 만약 새 줄이 안 흐른다면, 그 파일에 지금 아무 기록도 안 쌓이고 있다는 뜻이라 그것도 정상이에요.


Step 4: "복사하고 옮기고 이름 바꾸기 — cp와 mv"

이제 파일을 정리해봅시다. 정리의 기본은 복사하고, 옮기고, 이름을 바꾸는 거예요. 그런데 우리 연습장 파일들은 다 비어 있으니, 내용이 든 파일을 하나 들여와서 연습할게요. 아까 본 /etc/os-release를 우리 연습장으로 복사해 옵니다.

Bash
cd ~/practice
cp /etc/os-release server-info.txt

cpcopy예요. cp 원본 사본 순서로, "원본을 사본이라는 이름으로 복제하라"는 뜻이에요. 이제 연습장에 내용이 든 server-info.txt가 생겼어요. cat server-info.txt로 확인해보세요.

설정 파일을 고치기 전엔 항상 백업본을 하나 떠두는 게 좋아요. 똑같이 cp로요.

Bash
cp server-info.txt server-info.bak

이러면 원본은 그대로 두고 .bak이라는 안전 사본이 하나 더 생겨요. 폴더를 통째로 복사하고 싶으면 -r(recursive, 안쪽까지)을 붙입니다.

Bash
cp -r project project-backup

cp만 쓰면 폴더는 "디렉토리는 건너뜁니다" 하고 거부해요. -r을 붙여야 폴더와 그 안의 모든 것을 통째로 복제합니다.

이번엔 옮기기예요. mv(move)를 써요.

Bash
mv server-info.bak backup/

backup/이라는 폴더가 있으면 그 안으로 쏙 들어가요. 그런데 mv엔 비밀이 하나 있어요. 이름 바꾸기도 mv로 해요.

Bash
mv server-info.txt info.txt

옮긴 게 아니라 같은 자리에서 이름만 info.txt로 바뀌었어요. 리눅스엔 "이름 바꾸기" 전용 명령이 따로 없어요. mv가 그 일까지 합니다. 왜냐면 옮기기와 이름 바꾸기는 본질이 같거든요 — 둘 다 "이 파일의 새 위치(어느 폴더에, 어떤 이름으로)를 정하는 일"이에요.

cpmv의 차이를 그림으로 보면 이래요.

텍스트
  cp 원본 사본      원본은 그대로 두고 복제본을 하나 더 만든다
      a.txt ──┬──  a.txt   (그대로 남음)
              └──  b.txt   (새 사본)

  mv 원본 대상      원본을 그 자리에서 들어내 옮기거나 이름을 바꾼다
      a.txt ─────  b.txt   (a.txt는 사라짐)

⚠️ 한 가지 주의. cpmv로 옮긴 대상에 같은 이름의 파일이 이미 있으면, 경고 없이 덮어써서 원래 파일이 사라져요. 헷갈릴 땐 -i(interactive, 물어보기)를 붙이면 "덮어쓸까요? (y/n)" 하고 한 번 확인해줍니다. 이 -i는 다음 Step의 rm에서 더 중요하게 다시 만나요.

현업에선 설정 파일을 손대기 전에 cp config.yml config.yml.bak 한 줄 떠두는 게 거의 반사 신경이에요. 잘못되면 백업으로 되돌리면 되니까, 이 한 줄이 마음의 평화를 줍니다.

💡 한 줄 정리

복제는 cp(폴더는 -r), 옮기기와 이름변경은 mv 하나로. 덮어쓰기 사고가 걱정되면 -i로 물어보게 한다.

🙋 학생 질문 — "cp랑 mv를 쳤는데 아무 메시지도 안 뜨고 그냥 프롬프트만 돌아와요. 제대로 된 건가요?"

네, 잘 된 거예요. 리눅스 도구들은 "조용한 성공" 철학을 따라요. 성공하면 아무 말 없이 다음 프롬프트로 돌아오고, 문제가 생겼을 때만 메시지를 냅니다. 영어권에선 이걸 "no news is good news(무소식이 희소식)"라고 표현해요.

처음엔 "한 건가 안 한 건가" 불안하죠. 그럴 땐 ls로 결과를 눈으로 확인하면 돼요. 복사가 됐으면 사본이 보이고, 옮겼으면 원래 자리엔 없고 옮긴 자리에 있을 거예요. 이렇게 "치고 → ls로 확인" 습관을 들이면 마음이 편해집니다.


Step 5: "지울 땐 천천히 — rm의 위험과 안전 습관"

오늘 가장 조심해서 다룰 명령이 왔습니다. 바로 삭제, rm이에요. 어렵진 않아요. 다만 리눅스의 삭제는 윈도우와 결정적으로 다른 점이 하나 있어서, 그걸 먼저 분명히 알고 가야 해요.

Bash
rm debug.log

rmremove, 파일을 지워요. 그런데 여기서 윈도우·맥과 다른 점 — 리눅스엔 휴지통이 없어요. 윈도우에서 파일을 지우면 휴지통에 들어가서 나중에 복구할 수 있죠. 리눅스 서버의 rm은 그 자리에서 바로, 영구히 지웁니다. 되돌릴 휴지통이 없어요.

무섭게 들리죠? 그런데 겁먹을 일이 아니라 습관의 문제예요. 안전장치를 하나 소개할게요. -i(물어보기)예요.

Bash
rm -i error.log
텍스트
rm: remove regular file 'error.log'? 

지우기 전에 "정말 지울까요?" 하고 한 번 물어봐요. y를 누르면 지우고, n이면 멈춥니다. 확신이 안 설 땐 이 -i가 든든한 안전벨트예요.

폴더를 지울 땐 어떨까요? rm만으로는 폴더가 안 지워져요. -r(안쪽까지)을 붙여야 합니다.

Bash
rm -r project-backup

폴더와 그 안의 모든 것을 지워요. 빈 폴더만 지우고 싶다면 더 안전한 rmdir도 있어요.

Bash
rmdir emptydir

rmdir비어 있는 폴더만 지워요. 안에 뭔가 들어 있으면 "비어 있지 않습니다" 하고 거부합니다. 이 깐깐함이 오히려 안전장치예요 — 실수로 내용물째 날리는 걸 막아주거든요.

이제 가장 조심해야 할 조합을 짚을게요. rm -rf예요.

텍스트
  rm file        파일 하나 삭제 (휴지통 없음 = 즉시 영구)
  rm -i file     지우기 전에 y/n 으로 물어봄           안전
  rm -r dir      디렉토리 + 그 안의 모든 것 삭제
  rmdir dir      비어 있는 디렉토리만 삭제             안전장치
  rm -rf dir     묻지도 따지지도 않고 강제로 싹 삭제    가장 위험

-f(force, 강제)는 "묻지 말고, 없는 파일이어도 군말 없이 밀어붙여라"예요. -r과 합친 rm -rf는 폴더든 뭐든 묻지도 않고 통째로 날려버립니다. 강력한 만큼 위험해요.

⚠️ 절대 하지 말아야 할 것: rm -rf / (시스템 전체)나 rm -rf ~(내 홈 전체). 시스템이나 내 모든 파일을 한 줄에 날려버리는, 개발판의 전설 같은 사고예요. 특히 다음 Step에서 배울 와일드카드(*)와 섞이면 더 위험하니, 그땐 더 천천히 가야 해요.

그래서 이 과목에서 가장 강조하고 싶은 건 명령어 자체가 아니라 지우기 전의 습관이에요.

텍스트
  지우기 전 3초 습관
    1) ls 로 확인       "정말 이것들만 지워지는 게 맞나?" 눈으로 본다
    2) 중요하면 cp 로 백업
    3) 헷갈리면 rm -i    하나씩 y/n 으로 확인하며 지운다

솔직하게 말할게요. git 같은 도구엔 "되돌리기" 마법이 있지만, 리눅스 삭제엔 그게 없어요. 그래서 진짜 안전망은 "되돌릴 수 있다"가 아니라 "지우기 전에 신중한 습관"이에요. 이 정직함이 오히려 여러분을 지켜줘요. 그리고 안심하세요 — 현업의 고수일수록 rm 앞에서 더 천천히, 더 신중하게 합니다. 빨리 지우는 게 실력이 아니라, 확인하고 지우는 게 실력이에요.

💡 한 줄 정리

리눅스 삭제는 휴지통이 없어 되돌릴 수 없으니, rm 앞에서는 늘 ls로 확인하고 중요한 건 백업하는 습관이 진짜 안전망이다.

🙋 학생 질문 — "실수로 중요한 파일을 rm 해버렸어요. 윈도우 휴지통처럼 되살릴 방법이 정말 없나요?"

솔직히 말하면, 기본적으로는 없어요. 그래서 오늘 그렇게 "지우기 전 확인·백업·rm -i" 습관을 강조한 거예요. (전문 복구 도구가 아예 없는 건 아니지만, 성공을 장담할 수 없고 입문 단계에서 기댈 만한 방법이 아니에요. 진짜 안전망은 평소의 백업입니다.)

너무 자책하진 마세요. 사실 거의 모든 개발자가 한 번씩은 겪는 통과의례 같은 일이에요. 중요한 건 그 다음이에요 — 오늘부터 "지울 땐 일단 ls로 확인" 습관을 들이면, 같은 실수를 다시 할 일이 거의 없어집니다. 그게 이 사고에서 배워 갈 가장 값진 것이에요.


Step 6: "한 번에 여러 개 — 와일드카드와 글로빙"

파일이 수십, 수백 개일 때 하나씩 이름을 다 칠 순 없겠죠. ".log로 끝나는 것만", "이름이 app으로 시작하는 것만" 같은 식으로 무리 지어 다루는 방법이 있어요. 와일드카드(wildcard)라고 해요. 연습할 파일 몇 개를 만들어볼게요.

Bash
cd ~/practice
touch app1.log app2.log app10.log notes.txt readme.md

이제 와일드카드를 하나씩 써봅시다. 가장 많이 쓰는 건 *(별표)예요.

Bash
ls *.log
텍스트
app1.log  app10.log  app2.log

*는 "아무 글자든 0개 이상"을 뜻해요. 그래서 *.log는 "앞이 뭐든 .log로 끝나는 모든 것"이라 .log 파일 세 개만 골라줘요. notes.txtreadme.md는 빠졌죠.

다음은 ?(물음표). 이건 "정확히 한 글자"예요.

Bash
ls app?.log
텍스트
app1.log  app2.log

app?.logapp 다음에 딱 한 글자, 그 다음 .log예요. 그래서 app1.log·app2.log는 맞지만 app10.log10이 두 글자라 빠집니다. 이 차이가 와일드카드의 묘미예요.

[](대괄호)는 "괄호 안 글자 중 하나"예요.

Bash
ls app[12].log     # app1.log, app2.log 만

[12]는 "1 또는 2", [a-z]처럼 범위도 됩니다. 마지막으로 {}(중괄호)는 조금 달라요. 매칭이 아니라 나열한 것들로 펼치기예요. 새 파일을 한 번에 여러 개 만들 때 유용해요.

Bash
mkdir -p logs/{2024,2025,2026}
touch report-{jan,feb,mar}.txt

logs/ 아래 2024·2025·2026 폴더 세 개가, report-jan.txt·report-feb.txt·report-mar.txt 파일 세 개가 한 줄에 만들어져요.

여기서 꼭 짚고 넘어갈 핵심이 있어요. 와일드카드를 펼치는 건 명령어가 아니라 셸이에요. 무슨 말이냐면, 우리가 ls *.log를 치면 ls*.log를 받는 게 아니라, 셸이 먼저 *.log를 실제 파일명으로 바꿔치기한 다음 ls에 넘겨줘요.

텍스트
  내가 친 것:    rm  *.log
                     │
                       (셸이 먼저 펼친다)
  실제 실행:     rm  app1.log  app10.log  app2.log

그래서 와일드카드는 lscprm이든 모든 명령에서 똑같이 작동해요. 셸이 미리 펼쳐주니까요.

패턴
* 0글자 이상 무엇이든 *.log → 모든 .log
? 딱 한 글자 app?.logapp1.log (app10.log ✗)
[...] 괄호 안 한 글자 app[12].logapp1·app2
{a,b} 나열한 것들로 펼침 f{1,2}.txtf1.txt f2.txt

⚠️ 여기서 지난 Step의 안전 습관이 빛나요. rm *.log는 강력하지만, 한 칸 잘못 띄워 rm * .log라고 치면 *가 폴더의 모든 파일로 펼쳐져 싹 지워질 수 있어요. 그래서 rm에 와일드카드를 쓰기 전엔 반드시 같은 패턴으로 ls를 먼저 쳐서 "무엇이 지워질지" 눈으로 확인하세요. ls *.log로 확인 → 맞으면 rm *.log. 이 순서가 사고를 막아줍니다.

현업에선 "2026년 1월 로그만 지워줘" 같은 일을 rm access-2026-01-*.log 한 줄로 끝내요. 단, 늘 ls로 먼저 확인하고요.

💡 한 줄 정리

*·?·[]는 셸이 파일명으로 펼치는 와일드카드, {}는 단어를 나열로 펼친다. rm과 섞을 땐 같은 패턴으로 ls 먼저.

🙋 학생 질문 — "*가 와일드카드라면, ls *랑 그냥 ls는 결과가 비슷한데 뭐가 다른가요?"

좋은 관찰이에요. ls(그냥)는 ls가 직접 "지금 폴더에 뭐 있나 보여줘"를 처리해요. 반면 ls *는 셸이 먼저 *를 지금 폴더의 모든 항목 이름으로 펼친 뒤, 그 이름들을 ls에 인자로 넘겨요.

보통 결과는 비슷해 보이지만 차이가 있어요. *.으로 시작하는 숨김 파일은 펼치지 않고, 폴더가 끼면 그 폴더 '안'까지 보여주려 해요. 핵심은 결과의 차이가 아니라 "*는 셸이 미리 파일명으로 바꿔준다"는 원리예요. 이 원리를 알면 다음 Step의 find에서 따옴표를 왜 쓰는지도 자연스럽게 이해돼요.


Step 7: "어디 있더라 — find로 파일 찾기"

파일이 폴더 여기저기 흩어져 있으면 "그게 어디 있더라" 싶을 때가 있죠. 와일드카드는 지금 폴더(또는 지정한 한 곳)만 보지만, find는 하위 폴더까지 싹 뒤져서 찾아줘요.

Bash
find . -name "*.log"

읽는 법은 간단해요. find [어디서] [무슨 조건] 이에요. .은 "현재 폴더부터", -name "*.log"는 "이름이 .log로 끝나는 것". 그러면 현재 폴더와 그 아래 모든 폴더를 뒤져서 .log 파일을 다 찾아줍니다.

여기서 *.log를 따옴표로 감싼 게 중요해요. 지난 Step에서 배웠죠? 따옴표가 없으면 셸이 *.log를 먼저 펼쳐버려서 find가 제대로 못 뒤져요. 따옴표로 감싸면 셸이 안 건드리고 패턴 그대로 find에 넘겨, find가 하위 폴더까지 직접 펼치며 찾습니다.

조건은 이름 말고도 여럿이에요. 자주 쓰는 것만 볼게요.

Bash
find . -type f                 # 파일만 (d는 디렉토리만)
find . -name "*.log" -type f   # .log 이면서 파일인 것
find . -mtime +30              # 수정한 지 30일 넘은 것
find . -size +100M             # 100MB 넘는 큰 파일

-type은 파일(f)인지 폴더(d)인지, -mtime은 수정 시각(+30은 30일보다 오래된, -7은 최근 7일 이내), -size는 크기(+100M은 100MB 초과)예요. 조건을 여러 개 나란히 쓰면 "모두 만족하는 것"을 찾아줍니다.

찾은 걸 바로 처리할 수도 있어요. 예를 들어 find . -name "*.tmp" -delete는 찾자마자 지워요. 이렇게 "찾아서 바로 무언가 하기"를 파이프와 엮으면 훨씬 강력해지는데, 그건 다음다음 시간 주제니 오늘은 "찾기"에 집중할게요.

비슷한 도구 둘만 더 소개할게요.

Bash
locate bash      # 미리 만들어둔 색인에서 초고속 검색
which python3    # 명령어의 실제 위치 찾기  →  /usr/bin/python3

locate는 시스템이 미리 만들어둔 파일 색인(목록)에서 찾아 find보다 훨씬 빨라요. 대신 색인이 주기적으로 갱신돼서, 방금 만든 파일은 아직 못 찾을 수 있어요(필요하면 sudo updatedb로 갱신, 배포판에 따라 설치가 필요해요). which는 "내가 친 python3이 실제로 어디 있는 python3인가"를 알려줘요. 이건 나중에 환경변수를 배울 때 다시 만납니다.

현업에서 가장 자주 만나는 새벽 호출이 "운영 서버 디스크가 꽉 찼다"예요. 이때 find /var/log -name "*.log" -size +100M 한 줄로 용량을 잡아먹는 범인 로그를 단번에 찾아냅니다.

💡 한 줄 정리

find는 "어디서 + 무슨 조건"으로 하위 폴더까지 뒤져 찾는다(-name·-type·-mtime·-size). 빠른 색인 검색은 locate, 명령 위치는 which.

🙋 학생 질문 — "find . -name *.log 를 따옴표 없이 쳤더니 결과가 이상해요. 따옴표가 꼭 필요한가요?"

네, 그 따옴표가 생각보다 중요해요. 따옴표 없이 *.log를 쓰면, 지난 Step에서 배운 대로 셸이 먼저 *.log를 현재 폴더의 .log 파일들로 펼쳐서 find에 넘겨버려요. 그러면 find는 패턴이 아니라 이미 펼쳐진 파일 이름들을 받게 돼서, 하위 폴더 검색이 엉키거나 에러가 납니다.

"*.log"처럼 따옴표로 감싸면 셸이 손대지 않고 패턴 그대로 find에 전달해요. 그제서야 find가 직접 하위 폴더까지 내려가며 제대로 찾습니다. find에서 -name 패턴은 따옴표로 감싸는 습관을 들이면 좋아요.


Step 8: "묶고 압축하기 — tar·gzip·zip"

오늘의 마지막 조각, 정리의 꽃인 압축이에요. 시작하기 전에 한 가지 구분부터. "묶기"와 "압축"은 다른 일이에요. 묶기는 여러 파일을 하나의 꾸러미로 합치는 것, 압축은 그 크기를 줄이는 것. 리눅스에선 이 둘을 각각 다른 도구가 맡아요 — 묶기는 tar, 압축은 gzip이에요.

먼저 묶기. 연습장의 logs/ 폴더를 하나로 묶어볼게요.

Bash
tar -cf logs.tar logs/

tartape archive(옛날 테이프 백업에서 온 이름)예요. -c(create, 만들기) -f(file, 파일로). 그러면 logs/ 폴더가 logs.tar라는 꾸러미 하나로 묶여요. 아직 압축은 안 했으니 크기는 거의 그대로예요. 풀 땐 -x(extract, 꺼내기)를 써요.

Bash
tar -xf logs.tar

이제 압축. 파일 하나를 압축하는 건 gzip이에요.

Bash
gzip server-info.txt      # server-info.txt.gz 가 생기고 원본은 사라짐
gunzip server-info.txt.gz # 다시 풀기

그런데 실무에선 보통 "묶기 + 압축"을 한 번에 해요. tar-z(gzip) 옵션을 끼우면 됩니다. 이게 리눅스 세계의 표준 백업 방식이에요.

Bash
tar -czf logs.tar.gz logs/   # 묶고(c) 압축(z)해서 파일로(f)
tar -xzf logs.tar.gz         # 풀기 (x로 꺼내고 z로 압축 해제)
tar -tzf logs.tar.gz         # 안 풀고 안에 뭐가 들었는지 목록만 보기

외우는 법은 간단해요. 만들 땐 czf, 꺼낼 땐 xzf. 결과물 .tar.gz는 "tar로 묶고 gz로 압축했다"는 뜻이고, .tgz로 줄여 쓰기도 해요.

흐름을 한 줄로 보면 이래요.

텍스트
  흩어진 여러 파일  ──[ tar ]──►  하나로 묶음(.tar)  ──[ gzip ]──►  압축본(.tar.gz)

윈도우 쓰는 동료와 파일을 주고받을 땐 zip이 편해요. 윈도우가 기본으로 열 수 있거든요.

Bash
zip -r logs.zip logs/   # 묶기 + 압축을 한 번에 (-r 로 폴더 통째)
unzip logs.zip          # 풀기

정리하면, 리눅스 서버끼리는 tar.gz가 표준, 윈도우·일반 사용자와 교환할 땐 zip을 씁니다.

명령 하는 일
tar -czf x.tar.gz dir/ 묶고 + 압축 (만들기)
tar -xzf x.tar.gz 풀기
tar -tzf x.tar.gz 안 풀고 내용 목록만 보기
gzip file / gunzip file.gz 파일 하나 압축 / 풀기
zip -r x.zip dir/ / unzip x.zip 윈도우와 교환용 묶기·풀기

현업에선 한 달치 로그를 logs-2026-01.tar.gz 하나로 묶어 보관하고, 필요하면 그걸 다른 서버로 보내요. 서버 사이에 파일을 보내는 법은 나중에 SSH를 배울 때 다룰 거예요. 백업의 기본 단위가 바로 이 tar.gz랍니다.

그리고 압축을 풀면 원래 파일의 "권한"(누가 읽고 쓸 수 있는지)까지 그대로 살아나요. tar가 그 정보도 같이 묶어두거든요. 그 권한이라는 게 바로 ls -l을 쳤을 때 줄 맨 앞에 보이던 -rw-r--r-- 같은 10글자인데, 이걸 읽고 바꾸는 법이 다음 시간 주제예요.

💡 한 줄 정리

여러 개는 tar로 묶고 gzip으로 압축한다(한 번에 tar -czf, 풀 땐 -xzf). 윈도우와 교환할 땐 zip.

🙋 학생 질문 — "묶기(tar)랑 압축(gzip)이 왜 따로예요? 그냥 한 번에 하면 편할 텐데요."

지난 시간 유닉스 철학 기억나세요? "작은 도구 하나가 한 가지를 아주 잘한다"였죠. 그게 여기서도 그대로예요. tar는 "여러 개를 하나로 묶기"만, gzip은 "크기 줄이기"만 잘하는 작은 도구예요. 그리고 우리가 본 것처럼 tar -czf로 이어 쓰면 한 번에 되니, 불편하지도 않아요.

이렇게 나눠두면 좋은 점이 있어요. 만약 gzip보다 더 세게 압축하는 새 도구(예: xz, zstd 같은)가 나오면, tar는 그대로 두고 압축 부분만 갈아끼우면 돼요. 실제로 tar -cJf(xz 압축)처럼요. 묶기와 압축이 분리돼 있어서 가능한 유연함이에요. 하나로 합쳐 놨다면 통째로 새로 만들어야 했겠죠.


마무리

오늘 정말 잘 따라오셨어요. 지난 시간엔 리눅스 안을 걸어 다니기만 했는데, 이제 직접 파일을 만들고, 들여다보고, 옮기고, 안전하게 지우고, 찾아서 압축까지 할 수 있게 됐습니다. 내 손으로 리눅스를 다듬기 시작한 거예요. 오늘 배운 걸 세 가지로 정리할게요.

오늘 배운 핵심 세 가지

💡 하나 — 만들기(touch·mkdir -p), 보기(cat·less·head·tail·wc), 정리(cp·mv)로 파일을 자유롭게 다룬다. 짧은 건 cat, 긴 건 less, 필요한 만큼만 head/tail.

💡 — 리눅스 삭제엔 휴지통이 없다. rm 앞에서는 ls로 확인하고, 중요한 건 백업하고, 헷갈리면 rm -i로 한 번 더 묻게 하는 습관이 진짜 안전망이다. 와일드카드(*)와 섞일 땐 더 천천히.

💡 find로 하위 폴더까지 뒤져 찾고(-name·-mtime·-size), tar -czf로 묶어 압축해 깔끔하게 보관한다.

다음 시간 예고

오늘 파일을 실컷 만들면서 ls -l을 칠 때마다 줄 맨 앞에 -rw-r--r-- 같은 10글자가 따라다니는 걸 봤을 거예요. 압축을 풀 때 그 정보까지 같이 살아난다고도 했죠. 그 10글자가 바로 "누가 이 파일을 읽고, 쓰고, 실행할 수 있는가"를 말하는 권한이에요.

다음 시간(A-3)엔 이 10글자를 읽는 법을 익히고, chmod로 직접 바꿔봅니다. "방금 만든 스크립트에 실행권한을 주려면?" 같은 실전 상황도 다뤄요. 그리고 서버를 다루다 보면 누구나 한 번쯤 만나는 그 빨간 메시지 — Permission denied(권한 거부) — 를 무작정 sudo로 때우지 않고 스스로 푸는 법을 배웁니다. 그럼 다음 시간에 만나요.


과제

오늘 과제는 모두 여러분 자신의 리눅스 환경(WSL2·맥 터미널·VM)에서 직접 손으로 쳐보는 실습이에요. 한 단계 칠 때마다 ls로 결과를 확인하며 천천히 따라오세요. 특히 지우는 과제에선 "치기 전 ls로 확인" 습관을 꼭 지켜봅니다.

[기초] 연습장 차리고 정리하기

빈 연습장을 하나 차려서 만들고·복사하고·옮기는 흐름을 직접 익혀보세요.

  • ~/practice 아래에 mkdir -plogs/2026backup 폴더 구조를 한 번에 만든다
  • touchaccess.log·error.log·debug.log 세 파일을 만든다
  • cp/etc/os-releaseserver-info.txt라는 이름으로 연습장에 들여오고, .bak 백업본도 하나 더 만든다
  • mv로 그 백업본을 backup/ 폴더 안으로 옮긴다
  • 각 단계 전후로 ls(또는 ls -l)를 쳐서 무엇이 어떻게 바뀌는지 직접 적어본다

[응용] 안전하게 지우기 + 와일드카드

와일드카드로 여러 파일을 골라잡고, 안전 습관대로 지워보세요.

  • touchapp1.log·app2.log·app10.log·notes.txt를 만든다
  • ls *.log.log 파일만 골라 보고, 무엇이 매치됐는지 적는다
  • ls app?.logls app[12].log의 결과 차이를 비교하고, 왜 app10.log이 빠지는지 한 줄로 설명한다
  • "지우기 전 ls로 확인" 습관대로, 먼저 ls *.log로 무엇이 지워질지 확인한 뒤 rm -i *.log로 하나씩 y/n을 누르며 지운다
  • 만약 rm -rf로 지웠다면 무엇이 더 위험했을지 한 줄로 적어본다

[심화] 어질러진 로그 정리 (서버 상황 상상)

현업 상황을 상상해봅시다. "운영 서버의 로그 폴더가 꽉 차서, 오래된 로그를 찾아 묶어 압축해 보관해야 한다." 그 정리 작업을 연습장에서 직접 재현해보세요.

  • mkdir -p logs로 폴더를 만들고, touch로 여러 날짜 이름의 로그 파일을 만든다 (예: access-2026-01.log·access-2026-02.log 등)
  • find로 "이름이 .log로 끝나는 파일"을 하위 폴더까지 모두 찾아 목록을 낸다 (-name 패턴은 따옴표로 감싸기)
  • man find를 읽고 -mtime이나 -size 옵션을 찾아, "오래된 로그" 또는 "큰 로그"를 찾는 find 한 줄을 직접 만들어 실행해본다
  • 마지막으로 logs/ 폴더를 tar -czf logs-backup.tar.gz logs/로 묶어 압축하고, tar -tzf로 안에 무엇이 들었는지 확인한다

생각해볼 주제

1. 왜 리눅스는 "지우면 끝"으로 설계했을까

윈도우와 맥에는 휴지통이 있는데, 리눅스 서버의 rm엔 휴지통이 없어 한 번 지우면 되돌릴 수 없습니다. 언뜻 불편해 보이는 이 설계가 서버 환경에서는 오히려 합리적인 이유가 무엇일지 생각해보세요. 단순함, 디스크 자원, 동작의 예측 가능성, 자동화라는 네 단어를 실마리로 삼아보세요. 그리고 그 대가로 우리가 길러야 하는 습관은 무엇인지도 함께 정리해보세요.

2. 묶기(tar)와 압축(gzip)은 왜 다른 도구로 나뉘어 있을까

하나의 명령이 "묶고 압축까지" 다 하도록 만들 수도 있었을 텐데, 유닉스는 굳이 targzip을 따로 두었습니다. 지난 시간에 만난 "작은 도구가 한 가지만 잘한다"는 유닉스 철학을 떠올려보세요. 도구를 작게 쪼갠 이 선택이, 더 좋은 압축 방식이 새로 등장했을 때 어떤 유연함을 주는지 고민해보세요.

3. 와일드카드 *는 누가 펼치는가 — 명령어가 아니라 셸이 한다

rm *.log를 칠 때 *를 실제 파일명으로 펼치는 주체는 rm이 아니라 셸입니다. 이 사실이 왜 중요한지 두 갈래로 생각해보세요. 하나는 "왜 ls·cp·rm 등 모든 명령에서 와일드카드가 똑같이 동작하는가", 다른 하나는 "rm * .log처럼 한 칸 잘못 띄웠을 때 왜 그렇게 위험해지는가". 이 둘을 셸이 먼저 펼친다는 한 가지 원리로 연결해 설명해보세요.

✅ 예시 답안정답 보기

과제와 생각해볼 주제의 예시답안입니다. 모든 명령은 여러분 자신의 환경에서 직접 쳐보며 확인하는 게 가장 중요해요. 파일 이름이나 개수가 책과 조금 달라도 정상이니, 흐름이 맞는지를 보면 됩니다. 특히 지우는 과제에선 "치기 전 ls로 확인" 습관을 꼭 지켜보세요.


🎯 [과제 1 예시답안] 연습장 차리고 정리하기

채점 포인트

확인 항목 무엇을 보면 되는가
중첩 폴더 생성 mkdir -plogs/2026을 한 번에(중간 logs도 같이) 만들었는가
빈 파일 생성 touch로 세 파일을 한 줄에 만들었는가
외부 파일 복사 cp /etc/os-release server-info.txt로 내용 있는 파일을 들여왔는가
백업 후 이동 .bak을 만들고 mvbackup/ 안에 옮겼는가
단계별 확인 각 단계마다 ls로 무엇이 바뀌는지 직접 확인했는가

풀이 예시

Bash
$ cd ~/practice

# 중첩 폴더를 한 번에 — 중간 logs 폴더도 같이 생긴다
$ mkdir -p logs/2026 backup
$ ls
backup  logs

# 빈 파일 세 개를 한 줄로
$ touch access.log error.log debug.log
$ ls
access.log  backup  debug.log  error.log  logs

# 내용 있는 파일을 연습장으로 들여오고, 백업본도 하나 더
$ cp /etc/os-release server-info.txt
$ cp server-info.txt server-info.bak
$ ls
access.log  backup  debug.log  error.log  logs  server-info.bak  server-info.txt

# 백업본을 backup 폴더 안으로 옮기기
$ mv server-info.bak backup/
$ ls backup
server-info.bak

핵심은 mkdir -p logs/2026 한 줄로 logs와 그 안의 2026이 함께 만들어졌다는 점이에요. -p가 없었다면 "logs가 없는데요?" 하고 에러가 났을 거예요. 그리고 cp로 들여온 server-info.txt는 빈 파일이 아니라 /etc/os-release의 내용이 그대로 복사돼 있어요. cat server-info.txt로 확인해보세요.

💡 튜터의 한마디 — 작업을 시작할 때 폴더 구조부터 mkdir -p로 잡아두는 습관이 좋아요. 현업에서도 새 서비스를 올릴 때 로그·백업·설정 폴더를 먼저 만들어두고 시작하거든요. 그리고 한 단계 칠 때마다 ls로 확인하는 리듬을 들이면, 내가 지금 뭘 하고 있는지 놓치지 않습니다.

🎯 [과제 2 예시답안] 안전하게 지우기 + 와일드카드

채점 포인트

확인 항목 무엇을 보면 되는가
* 매칭 ls *.log.log 파일만 골라냈는가
?[] 차이 app?.log·app[12].log에서 app10.log이 빠진 이유를 설명했는가
확인 후 삭제 지우기 전 ls *.log로 먼저 확인했는가
안전한 삭제 rm -i로 하나씩 y/n 확인하며 지웠는가
위험 인식 rm -rf였다면 무엇이 위험했을지 적었는가

풀이 예시

Bash
$ touch app1.log app2.log app10.log notes.txt

# * 는 "아무 글자든" — .log 로 끝나는 셋만
$ ls *.log
app1.log  app10.log  app2.log

# ? 는 "딱 한 글자" — app10.log 은 빠진다
$ ls app?.log
app1.log  app2.log

# [12] 는 "1 또는 2 한 글자" — 역시 app10.log 은 빠진다
$ ls app[12].log
app1.log  app2.log

# 지우기 전 — 무엇이 지워질지 먼저 눈으로 확인!
$ ls *.log
app1.log  app10.log  app2.log

# 확인했으니 하나씩 물어보며 지우기
$ rm -i *.log
rm: remove regular file 'app1.log'? y
rm: remove regular file 'app10.log'? y
rm: remove regular file 'app2.log'? y

app10.logapp?.logapp[12].log에서 빠진 이유가 이 과제의 핵심이에요. ?는 정확히 한 글자, [12]도 한 글자(1 또는 2)인데, app10.logapp 다음이 10으로 두 글자라 어느 쪽에도 안 맞아요. 반면 *는 글자 수에 상관없으니 셋 다 골라냈죠.

만약 rm -rf *.log였다면? -f가 확인 질문 없이 강제로 밀어붙이니, ls로 미리 확인하지 않았다면 무엇이 지워졌는지도 모른 채 끝났을 거예요. 더 위험한 건 한 칸 잘못 띄운 rm -rf * .log예요. *가 폴더의 모든 파일로 펼쳐져 notes.txt까지 싹 지워졌을 겁니다.

💡 튜터의 한마디 — 와일드카드와 rm을 함께 쓸 땐 "같은 패턴으로 ls 먼저, 그 다음 rm" 순서가 몸에 배어야 해요. ls *.log로 지워질 목록을 눈으로 확인한 뒤 그 줄을 rm으로 바꿔 치면, 실수가 끼어들 틈이 없습니다.

🎯 [과제 3 예시답안] 어질러진 로그 정리 (서버 상황 상상)

채점 포인트

확인 항목 무엇을 보면 되는가
로그 환경 재현 mkdir·touch로 날짜 이름의 로그 여러 개를 만들었는가
하위까지 찾기 findlogs/ 안쪽 파일까지 찾아냈는가
패턴 따옴표 -name "*.log"처럼 패턴을 따옴표로 감쌌는가
옵션 직접 탐색 man find-mtime/-size를 찾아 한 줄을 만들었는가
묶어 압축 tar -czf로 압축하고 tar -tzf로 내용을 확인했는가

풀이 예시

Bash
# 운영 서버 로그 폴더를 흉내 — 여러 날짜의 로그 만들기
$ mkdir -p logs
$ touch logs/access-2026-01.log logs/access-2026-02.log logs/error-2026-01.log

# 하위 폴더까지 뒤져 .log 전부 찾기 (패턴은 따옴표로!)
$ find . -name "*.log"
./logs/access-2026-01.log
./logs/access-2026-02.log
./logs/error-2026-01.log

# man find 로 찾은 옵션 — 30일 넘게 안 건드린 로그
$ find . -name "*.log" -mtime +30

# (결과가 비어 있어도 정상! 방금 만든 파일이라 30일이 안 됐으니까)

# 100MB 넘는 큰 파일 찾기 — 디스크 청소 범인 색출
$ find . -size +100M

# logs 폴더를 묶어서 압축
$ tar -czf logs-backup.tar.gz logs/

# 안 풀고 안에 뭐가 들었는지 확인
$ tar -tzf logs-backup.tar.gz
logs/
logs/access-2026-01.log
logs/access-2026-02.log
logs/error-2026-01.log

find . -name "*.log" -mtime +30을 쳤는데 아무것도 안 나오는 게 오히려 정상이에요. 방금 만든 파일이라 수정한 지 30일이 안 됐거든요. 실제 운영 서버라면 오래된 로그들이 주르륵 잡혔을 거예요. 이렇게 "오래된 것만", "큰 것만" 조건을 거는 게 find의 진짜 힘이에요. 마지막으로 tar -tzf는 압축을 풀지 않고도 꾸러미 안을 들여다보게 해줘서, 백업이 제대로 들어갔는지 확인할 때 유용합니다.

💡 튜터의 한마디 — "디스크가 꽉 찼다"는 현업에서 가장 흔한 새벽 호출 중 하나예요. 그때 find로 범인(오래되거나 거대한 로그)을 찾아 tar.gz로 묶어 보관하고 원본을 정리하는 흐름이 오늘 과제 그대로예요. 옵션을 다 외울 필요 없어요. man find로 그때그때 찾아 쓰면 됩니다.


🤔 [생각해볼 주제 1] 왜 리눅스는 "지우면 끝"으로 설계했을까

문제 상황 요약

윈도우와 맥에는 휴지통이 있는데, 리눅스 서버의 rm엔 휴지통이 없어 한 번 지우면 되돌릴 수 없습니다. 언뜻 불편해 보이는 이 설계가 서버 환경에서는 왜 오히려 합리적일까요?

튜터의 가이드 및 해설

실마리였던 네 단어로 풀어볼게요.

  • 단순함 — 휴지통은 "지운 파일을 어딘가 숨겨두고, 용량을 관리하고, 나중에 비우는" 복잡한 장치예요. 리눅스의 rm은 "지우라면 지운다"로 단순합니다. 동작이 단순하면 예외도 적고 믿고 쓸 수 있어요.
  • 디스크 자원 — 휴지통은 "지웠지만 아직 안 비운" 파일이 디스크를 계속 차지해요. 용량이 빠듯한 서버에서 "지웠는데도 공간이 안 늘어나는" 상황은 곤란하죠. rm은 즉시 공간을 돌려줍니다.
  • 예측 가능성rm을 치면 "지금, 영구히" 지워진다는 게 항상 같아요. "이건 휴지통으로, 저건 영구 삭제로" 같은 갈래가 없어 결과가 또렷합니다.
  • 자동화 — 스크립트가 자동으로 도는데 휴지통이 가득 차 멈추거나, 지운 줄 알았던 파일이 남아 있으면 사고로 이어져요. "지우면 끝"이 자동화엔 오히려 안전한 약속이에요.

대신 그 대가로 우리가 길러야 하는 건 분명해요. 되돌릴 장치가 없으니, 안전망을 도구가 아니라 습관에 둬야 한다는 거예요. 지우기 전 ls로 확인하고, 중요한 건 미리 백업하고, 헷갈리면 rm -i로 한 번 더 묻게 하는 것. 도구가 주지 않는 안전을 내 습관이 채우는 셈이에요.

💡 핵심을 한마디로

"리눅스의 '지우면 끝'은 불친절이 아니라, 단순함·자원 효율·예측 가능성·자동화를 위한 설계 선택입니다. 대신 안전망을 도구가 아닌 습관 — 확인·백업·rm -i — 에 두는 것이 그 설계와 함께 가는 개발자의 자세입니다."

🤔 [생각해볼 주제 2] 묶기(tar)와 압축(gzip)은 왜 다른 도구로 나뉘어 있을까

문제 상황 요약

하나의 명령이 "묶고 압축까지" 다 하게 만들 수도 있었을 텐데, 유닉스는 굳이 tar(묶기)와 gzip(압축)을 따로 두었습니다. 이 분리가 왜 더 유연할까요?

튜터의 가이드 및 해설

지난 시간에 만난 "작은 도구가 한 가지만 잘한다"는 유닉스 철학이 여기서도 그대로예요. tar는 "여러 개를 하나로 묶기"만, gzip은 "크기 줄이기"만 책임집니다. 그리고 tar -czf로 이어 쓰면 한 번에 되니, 사용자 입장에선 불편하지도 않죠.

이 분리가 빛나는 순간은 "더 좋은 압축 방식이 새로 나왔을 때"예요. 실제로 gzip 이후 xz, zstd처럼 더 세거나 빠른 압축 도구들이 등장했어요. 만약 묶기와 압축이 한 덩어리였다면, 새 압축 방식을 쓰려고 그 거대한 도구를 통째로 다시 만들어야 했을 거예요.

하지만 분리돼 있으니 tar는 그대로 두고 압축 부분만 갈아끼우면 됩니다. tar -czf(gzip)를 tar -cJf(xz)로 바꾸는 식으로요. 묶는 일은 변할 이유가 없고, 압축 기술만 발전하니, 변하는 부분과 변하지 않는 부분을 갈라둔 설계가 시간이 지날수록 이득을 줍니다.

💡 핵심을 한마디로

"묶기와 압축을 한 도구에 합쳤다면 새 압축 방식이 나올 때마다 전체를 새로 만들어야 합니다. 둘을 나눠두면 변하지 않는 tar는 그대로 두고 변하는 압축 부분만 교체할 수 있죠. 변할 것과 변하지 않을 것을 가르는 것, 그게 유닉스식 설계의 핵심입니다."

🤔 [생각해볼 주제 3] 와일드카드 *는 누가 펼치는가 — 명령어가 아니라 셸이 한다

문제 상황 요약

rm *.log를 칠 때 *를 실제 파일명으로 펼치는 주체는 rm이 아니라 셸입니다. 이 사실이 왜 중요한지를, "모든 명령에서 똑같이 동작하는 이유"와 "한 칸 잘못 띄웠을 때의 위험"이라는 두 갈래로 설명해보세요.

튜터의 가이드 및 해설

핵심은 순서예요. 우리가 rm *.log를 엔터 치면, rm*.log를 받는 게 아니에요. 셸이 먼저 *.log를 현재 폴더의 실제 파일명들로 바꿔치기한 다음, 그 결과를 rm에 넘깁니다.

Bash
# 내가 친 것
$ rm *.log
# 셸이 펼친 뒤 실제로 실행되는 것
$ rm app1.log app10.log app2.log

첫 번째 갈래 — 왜 모든 명령에서 똑같이 동작하나. 와일드카드를 펼치는 게 셸이지 개별 명령이 아니기 때문이에요. lscprm이든, 명령에 닿기 전에 셸이 이미 파일명으로 펼쳐서 넘겨줘요. 그래서 명령마다 따로 와일드카드 기능을 만들 필요가 없고, 어디서나 일관되게 작동합니다. (반대로, 명령이 패턴을 직접 받길 원하면 find . -name "*.log"처럼 따옴표로 감싸 셸의 펼침을 막아야 해요.)

두 번째 갈래 — 왜 한 칸이 위험한가. rm *.log는 ".log로 끝나는 것"이지만, 실수로 rm * .log라고 띄우면 셸은 이를 두 덩어리로 봐요. *(폴더의 모든 파일)와 .log(그런 이름의 파일)로요. 그러면 *가 폴더의 모든 파일로 펼쳐져 rm에 넘어가니, 의도와 전혀 다르게 전부 지워집니다. 셸이 먼저 펼친다는 원리를 모르면 이 사고가 왜 났는지조차 알기 어려워요.

그래서 결론은 같아요. 와일드카드와 rm을 함께 쓰기 전엔, 같은 패턴으로 ls를 먼저 쳐서 "셸이 무엇으로 펼치는지"를 눈으로 확인하는 거예요.

💡 핵심을 한마디로

"와일드카드는 명령어가 아니라 셸이 펼칩니다. 덕분에 모든 명령에서 일관되게 동작하지만, rm * .log처럼 한 칸만 잘못 띄워도 *가 전체 파일로 펼쳐져 위험해집니다. 그래서 rm 전에 같은 패턴으로 ls를 먼저 쳐 셸이 무엇으로 펼치는지 확인하는 습관이 필요합니다."

전체 목록 리눅스