AI의 답을 직접 실행
에게 "이 폴더의 파일들을 이렇게 정리해줘"라고 부탁하면 AI는 으로 답할 때가 많습니다. 그래서 쉘을 읽을 줄 알아야 AI의 답이 안전한지 스스로 검증할 수 있습니다.
로그인해야 쓸 수 있는 메뉴입니다.
로그인쉘 프로그래밍(bash)을 브라우저 안에서 도는 진짜 리눅스 터미널에서 단원별 미션으로 배워요. 1단원부터 명령의 결과를 예상하고 직접 실행해 보세요.
에게 해 달라고 하면 정말 다 해 줍니다. 하지만 아무것도 모른 채 모두 맡기기만 하면 인공지능에 얽매이게 되고, 인공지능이 한 일을 마치 내가 직접 한 것처럼 착각하게 됩니다.
중요한 일을 맡긴 상사가 업무 내용을 전혀 모른다고 생각해 보세요. 직원이 일을 잘해도 결과를 판단하기 어렵고, 그 직원이 떠나면 일을 이어 가기도 어렵습니다. AI에게 일을 맡길 때도 기본 지식이 필요한 이유입니다.
인공지능도 마찬가지입니다. 기본을 아는 사람만이 인공지능이 한 일을 이해하고, 맞는지 확인하고, 막혔을 때 스스로 이어 갈 수 있습니다. 인공지능을 부리는 사람이 되려면 기본을 알아야 합니다.
는 그 기본 중의 기본이자 시작점입니다. 쉘 명령어를 배우면 를 다루는 법과 관리의 기초를 익히게 되고, 그다음 단계가 바로 서버를 직접 운영하는 일입니다.
두려워하지 마세요. 모르는 명령은 인공지능에게 물어보며 쉽게 배울 수 있습니다. 한 줄씩 직접 쳐 보면서 차근차근 공부해 나가면 됩니다.
를 배우면 을 먼저 떠올리지만, AI 도구를 설치하고 실행하는 데는 와 이 든든한 기본기가 됩니다.
쉘은 AI 을 직접 만드는 주력 언어는 아니지만, 파이썬보다 오래전부터 파일 관리와 작업 에 쓰여 온 도구입니다.
깊이 공부할 필요 없이, 자주 쓰는 명령어 몇 가지만 익혀 보세요. 쉽게 시작해 평생 활용할 기본기가 됩니다.
은 실행, 파일 관리, 개발 에 쓸모가 많아요. 하지만 는 ·앱·노트북· 로도 쓸 수 있으니, 모든 AI 사용자가 을 꼭 써야 하는 것은 아니에요.
기초 부터 ·개발 도구, ·· 같은 다른 언어 실행, 까지 짧게 배우고 바로 실행해 보세요.
을 열고, 파일을 다루고, 글을 찾아 세고, 을 이어 붙입니다. 이 네 단원만 끝내도 터미널을 혼자 쓸 수 있어요.
값을 담고(), 판단하고 되풀이하고(조건·반복), 묶음에 이름을 붙여() 나만의 를 안전하게 만듭니다.
와 개발 도구를 설치하고, 에서 ···을 부려 실제 일을 합니다.
모든 이 함께 지키는 골격을 모았습니다 — 자리···잇는 기호. 처음 보는 명령도 읽을 수 있게 됩니다. 이 단원은 먼저 읽어도 됩니다.
실습 은 진짜 컴퓨터입니다. 빈 를 직접 준비하고, 인터넷에서 받고 설치해 봅니다 — 실제 에서 쓰는 순서 그대로입니다. 그리고 ·· | 처럼 매일 쓰는 도구의 을 익힙니다.
에게 "이 폴더의 파일들을 이렇게 정리해줘"라고 부탁하면 AI는 으로 답할 때가 많습니다. 그래서 쉘을 읽을 줄 알아야 AI의 답이 안전한지 스스로 검증할 수 있습니다.
쉘은 수십 년 동안 이 크게 바뀌지 않아 ·· 어디에나 있는 "컴퓨터의 공용어"입니다. 한 번 배워 두면 macOS·Linux·서버··AI 도구 어디서든 오래 써먹습니다.
macOS의 기본 쉘은 이지만, 이 과정의 기본 명령과 는 대부분 그대로 쓸 수 있습니다. 다만 zsh은 없는 를 공백으로 나누는 방식과 번호가 bash와 다릅니다. 는 bash 기준으로 배우세요. 첫 줄의 는 직접 실행할 때 bash를 쓰라는 뜻입니다. macOS 기본 bash 3.2에는 -A 같은 기능이 없으므로, 이런 예제는 이 과정의 실습 에서 따라 하세요.
20줄 남짓한 로, 에 실제로 페이지를 돌려주는 를 띄울 수 있습니다. 가 결국 "텍스트 한 덩어리를 주고받는 약속"임을 보여 주는 예제입니다.
#!/bin/bash
PORT=8084
PIPE=simple-web-server-pipe
rm -f "$PIPE"
mkfifo "$PIPE"
response() {
read -r method path _
echo "[$(date)] $method $path" >&2
index=$(cat index.html)
printf 'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n%s' \
"$index"
}
while true; do
response < "$PIPE" | nc -l "$PORT" > "$PIPE"
done
mkfifo "$PIPE"
를 만듭니다. 가 받은 요청과 우리가 만든 응답이 이 통로로 오갑니다.
nc -l "$PORT"
nc(netcat) 로 8084 를 열고 브라우저 접속을 기다립니다. 서버를 한 줄로 대신합니다.
response()
(메서드·)을 읽어 남기고, 을 HTTP 응답으로 만들어 돌려줍니다.
while true; do … done
응답을 마치고 연결이 끊기면 가 다시 돌아 다음 손님을 받습니다. 덕분에 서버가 계속 살아 있습니다.
같은 폴더에 index.html 을 두고 bash server.sh 로 실행한 뒤, 브라우저에서 :8084 를 열어 보세요. 실서비스용은 아니지만 HTTP 의 원리를 이해하기에 좋습니다.
쉽게 말하면 컴퓨터와 글자로 나누는 첫 대화입니다. 한 줄 말하면 한 줄 대답합니다.
쉽게 말하면 파일 탐색기에서 마우스로 하던 만들기·복사·이동·삭제를 글자로 합니다.
쉽게 말하면 아주 긴 글에 쓰는 형광펜·줄 세우기·개수 세기 도구입니다.
쉽게 말하면 컨베이어 벨트처럼 의 결과를 다음 명령으로 넘기고, 끝에서 상자(파일)에 담습니다.
쉽게 말하면 이름표 붙인 상자에 값을 넣어 두고, 나중에 이름으로 꺼내 쓰는 것입니다.
쉽게 말하면 '비가 오면 우산을 챙긴다', '계단을 열 번 오른다'처럼 판단과 되풀이를 시킵니다.
쉽게 말하면 자주 하는 일을 레시피 카드로 적어 두고 이름만 부르면 해 주게 만듭니다.
쉽게 말하면 도미노처럼 앞 일이 성공해야 다음 일이 넘어가게 만듭니다.
쉽게 말하면 안전벨트처럼 와 안전 이 사고를 미리 막아 줍니다.
쉽게 말하면 코드용 처럼 이 도구를 받아 오고, 가 를 실행합니다.
쉽게 말하면 새 작업실에 공구를 들여놓고 하나씩 잘 되는지 확인하는 일입니다.
쉽게 말하면 통역사처럼 이 ·· 에게 일을 맡기고 결과를 받아 옵니다.
쉽게 말하면 '숫자 세 개-숫자 네 개' 같은 모양 도장으로 맞는 글을 모두 찾습니다.
쉽게 말하면 칸마다 이름이 적힌 서류와 같아요. 칸을 알면 어떤 서류든 채웁니다.
쉽게 말하면 새 컴퓨터를 처음 꾸미는 것과 같아요. 빈 를 준비하고, 앱을 내려받아 설치합니다.
쉽게 말하면 레고 설명서와 같아요. 모양을 알면 어떤 작품이든 같은 순서로 끼웁니다.
[] 형태의 기본 구조로 명령을 입력할 수 있다
를 확인하고 폴더 사이를 이동할 수 있다
로 화면에 원하는 글자를 출력할 수 있다
man 과 로 모르는 명령어를 스스로 찾아볼 수 있다
이 필요한 명령 앞에 붙이기
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령
뒤에 아무것도 필요 없는 도 있습니다 — 이름 하나가 명령 전부입니다.
명령 옵션 대상
거의 모든 이 지키는 골격입니다 — 무엇을 할지, 어떻게 할지, 무엇에 할지.
cd 어디로
는 옮겨 갈 곳 하나만 받습니다. 비워 두면 로 갑니다.
echo 글자
는 건넨 글을 그대로 찍어 주니, 공백이 있으면 로 묶으세요.
따라 해 보기 예제를 누르면 명령이 실습 터미널 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
은 글자로 을 입력하는 창입니다. 그 안에서 명령을 실행하는 이 이며, 이 과정에서는 를 씁니다. $나 % 같은 는 명령을 입력할 차례라는 표시입니다. 표시 뒤에 명령을 적고 Enter를 누르세요. 이렇게 글자로 컴퓨터를 다루는 방식을 (명령줄 인터페이스)라고 합니다.
자세히 프롬프트에는 $ 말고도 더 많은 정보가 보이곤 합니다. 많은 컴퓨터에서 you@laptop:~$ 처럼 나오는데, 사용자 이름·컴퓨터 이름·지금 있는 폴더(~ 는 )·$ 순서입니다. 명령이 실행되는 동안에는 프롬프트가 사라졌다가 끝나면 다시 나타나므로, 프롬프트가 안 보이면 쉘이 아직 일하는 중이라는 뜻입니다. 명령이 멈춘 것 같으면 로 멈추고 프롬프트를 되찾습니다.
대부분의 는 "무엇을 할지(명령어) + 어떻게 할지() + " 세 부분으로 되어 있습니다. 예를 들어 -l notes.txt 는 "목록 보기(ls) + 자세히(-l) + notes.txt 파일"이라는 뜻입니다. 모르는 명령은 man 뒤에 그 이름을 쓰거나 명령 뒤에 를 붙이면 설명서를 볼 수 있습니다(실습 에서도 진짜 설명서가 열리고, q 를 누르면 닫힙니다).
자세히 옵션은 보통 대시(-)로 시작합니다. 대시 하나에는 한 글자짜리 짧은 옵션이 오고, 여러 개를 붙여 쓸 수 있어 ls -l -a 와 ls -la 는 같습니다. 대시 두 개에는 ls --all 처럼 읽기 쉬운 긴 이름이 옵니다. 인자는 명령이 다룰 대상으로 보통 파일이나 폴더 이름이며, ls notes.txt photos 처럼 여러 개를 한 번에 받는 명령도 많습니다. 이름에 공백이 있으면 로 감싸야 하나의 인자로 남습니다.
에서는 항상 "지금 어느 폴더에 있는가"가 중요합니다. 로 를 확인하고, 로 폴더를 옮겨 다니며, 로 그 안에 무엇이 있는지 봅니다. ~ 는 내 를, .. 는 를 뜻합니다.
자세히 는 파일의 주소입니다. 절대 경로는 맨 위인 / 에서 시작합니다(예: /home/you/notes.txt). 그래서 어디서든 통합니다. 상대 경로는 지금 있는 곳에서 시작합니다(photos/cat.jpg). 그래서 알맞은 폴더에서만 통합니다. cd 만 치면 곧장 홈 폴더로 가고, cd - 는 바로 전에 있던 폴더로 돌아갑니다. 이름을 치다가 Tab 을 누르면 이 나머지를 채워 주어() 오타가 줄어듭니다.
이 화면에서는 아무것도 설치하지 않고 실습 에서 바로 연습합니다. 에서는 이면 터미널 앱( 에서 '터미널' 검색)을, 면 시작 메뉴에서 을 엽니다. 이 과정과 같은 을 Windows 에서 쓰려면 을 설치하고 를 엽니다. 대부분의 에서는 +Alt+T 를 누릅니다.
자세히 Mac 의 기본 은 zsh 인데, 이 과정의 명령을 거의 다 알아듣습니다. 여기와 똑같은 쉘을 쓰고 싶으면 bash 라고 치세요. PowerShell 에서는 ·· 같은 몇몇 이름은 되지만 동작이 다르고 없는 명령도 많아서, Windows 에서는 WSL 을 권합니다. 어디서든 화살표 키로 앞서 친 명령을 불러올 수 있습니다 — 다시 치지 말고 ↑ 를 눌러 그대로 실행하거나 고쳐 쓰세요.
컴퓨터 전체를 바꾸는 일 — 설치나 같은 시스템 폴더에 쓰기 — 은 관리자()의 몫이라, 그냥 하면 라고 나옵니다. 앞에 를 붙이면 같은 명령이 그 권한으로 돌아갑니다 — sudo add tree 처럼요. 실습 은 비밀번호를 묻지 않고, 에서는 로그인 비밀번호를 칩니다. 꼭 필요한 명령에만 씁니다.
자세히 sudo는 보통 명령 하나를 관리자 권한으로 실행합니다. 프로그램 설치(apk add· install), /etc· 수정, 연결 등에 씁니다. sudo가 실수를 막아 주는 것은 아니므로 실행할 명령과 대상을 먼저 확인하세요. 에서 권한 오류가 나면 파일의 와 권한부터 살펴보세요. install -g도 설치 위치에 따라 sudo가 필요하지 않을 수 있습니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
ls -la ~/projects
ls: 폴더 안에 무엇이 있는지 목록을 보여 줍니다.-l자세히(long): 한 줄에 하나씩, ··크기·날짜와 함께 보여 줍니다.-a전부(all): 이름이 점으로 시작하는 ( 등)까지 보여 줍니다.~/projects: (~) 안의 projects 폴더입니다. 빼면 지금 있는 폴더를 보여 줍니다.total 16 drwxr-xr-x 5 you staff 160 Oct 17 09:12 . drwxr-xr-x 20 you staff 640 Oct 17 09:10 .. -rw-r--r-- 1 you staff 18 Oct 17 09:11 .env -rw-r--r-- 1 you staff 512 Oct 17 09:11 notes.txt drwxr-xr-x 3 you staff 96 Oct 17 09:12 site
한 줄이 항목 하나입니다. 첫 글자가 d 면 폴더, - 면 파일이고, 이어지는 는 누가 읽기·쓰기·실행을 할 수 있는지입니다. 그다음이 주인, 단위 크기, 마지막으로 바뀐 날짜, 이름입니다. . 은 그 폴더 자신, .. 은 이고, 맨 윗줄(total)은 사용량이라 넘어가도 됩니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
이것이 | 입니다. 왼쪽 이 찍어 낸 것이 화면으로 가지 않고 오른쪽 명령 안으로 곧장 들어갑니다. 제대로 배우는 곳은 4단원이지만 여기서부터 모든 단원에 나오니, "그러고 나서 그대로 건네준다"로 읽으면 됩니다.
ls|wc -l
가 파일을 늘어놓고 -l 이 그 줄 수를 세니, 나오는 것은 "파일이 몇 개인가"입니다.
cat notes.txt|head -3
은 파일 전체를 찍고, -3 은 그중 앞 세 줄만 남깁니다.
echo "hello shell"|wc -c
가 보낸 글을 -c가 수로 셉니다. 끝의 도 포함하며, 파일에는 저장하지 않습니다.
폴더와 빈 파일을 로 만들 수 있다
파일을 복사·이동·이름 변경·삭제할 수 있다
파일 내용을 ·· 로 확인할 수 있다
삭제 명령의 위험성을 이해하고 안전하게 사용할 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
mkdir 옵션 대상
폴더를 만듭니다. -p 를 붙이면 가는 길의 위 폴더까지 함께 만듭니다.
cp 옵션 대상 어디로
복사는 자리가 둘입니다 — 무엇을 복사할지, 그다음 어디로 갈지. 폴더째 복사하려면 -r 이 필요합니다.
mv 대상 어디로
옮기기와 이름 바꾸기는 같은 골격입니다 — 새 폴더를 적으면 옮기고, 새 이름을 적으면 이름이 바뀝니다.
rm 옵션 대상
적은 것을 지웁니다. 휴지통이 없으니 -i 로 먼저 물어보게 하세요.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
은 새 폴더를, 는 빈 파일을 만듭니다. mkdir -p a/b/c 처럼 -p 를 붙이면 까지 한 번에 만들어 줘서 편리합니다. 대부분의 처럼 성공하면 아무것도 출력하지 않으니, 로 결과를 확인하세요.
자세히 touch 에는 두 번째 일이 있습니다. 파일이 이미 있으면 내용은 그대로 두고 '마지막으로 바뀐 시각'만 새로 고치므로, 두 번 실행해도 안전합니다. 반대로 mkdir 은 폴더가 이미 있으면 'File exists' 라고 불평하는데, -p 를 붙이면 있는 폴더는 조용히 넘어갑니다. 이름에 공백이 있으면 가 필요해서(mkdir "my notes"), 많은 사람이 공백 대신 - 나 _ 를 씁니다.
는 원본을 남겨 두고 복사본을 만듭니다. 는 파일을 옮기거나 이름을 바꿉니다. 둘 다 원본을 먼저, 목적지를 나중에 적습니다. 예를 들어 mv memo.txt diary.txt는 같은 폴더에서 memo.txt의 이름을 diary.txt로 바꿉니다.
자세히 마지막 가 이미 있는 폴더면 cp 와 mv 는 파일을 같은 이름으로 그 안에 넣습니다. cp a.txt b.txt / 은 두 파일을 backup 에 복사합니다. 폴더를 통째로 복사하려면 -r()을 붙여야 하고, 안 붙이면 cp 가 거절합니다. mv 는 없이도 폴더를 옮깁니다. mv 로 이름을 바꾸는 것은 아주 큰 파일도 순식간인데, 이름만 바뀌고 내용은 복사하지 않기 때문입니다.
은 파일 전체를 보여 주고, 는 앞부분 몇 줄, 은 끝부분 몇 줄만 보여 줍니다. 은 파일을 삭제하는데 휴지통을 거치지 않고 즉시 영구 삭제되므로 조심해야 합니다.
자세히 head 와 tail 은 따로 말하지 않으면 10줄을 보여 주고, head -n 3 은 세 줄을 보여 줍니다. tail -f 는 파일을 계속 지켜보며 새로 붙는 줄을 바로 보여 주어, 이 도는 동안 볼 때 씁니다( 로 멈춤). 긴 파일은 less 로 보세요. 한 화면씩 보여 주며 Space 로 넘기고, / 로 찾고, q 로 나갑니다. rm 은 휴지통을 거치지 않으니, 같은 이름이나 으로 먼저 해 보고 나서 rm 하는 습관이 좋습니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
cp -r photos backup/photos-2026
cp: 복사합니다.-r: 폴더와 그 안의 모든 것을 복사합니다. -r 이 없으면 는 폴더 복사를 거절합니다.photos원본: 복사할 폴더입니다.backup/photos-2026대상: 안에 photos-2026 이라는 이름으로 복사본이 생깁니다. backup 폴더는 미리 있어야 합니다.아무것도 나오지 않습니다 — 이런 명령은 성공하면 조용합니다.
복사가 되면 cp 는 아무것도 출력하지 않습니다. backup 으로 확인하면 photos-2026 이 보여야 합니다. backup 이 없으면 '' 가 나오니, -p backup 으로 먼저 만들고 다시 복사하세요.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
ls -l|head -3
자세한 목록은 화면을 넘길 만큼 길어서, -3 으로 앞 세 줄만 봅니다.
mkdir -p backup&&cp notes.txt backup/&&ls backup
앞이 됐을 때만 다음으로 넘어갑니다 — 는 "그게 됐을 때만"이고, 마지막이 결과를 보여 줍니다.
ls photos|wc -l
photos 폴더를 열어 보지 않고 그 안에 몇 개가 있는지 셉니다.
으로 특정 단어가 든 줄을 찾을 수 있다
grep 의 -i·-n 을 활용할 수 있다
로 줄을 정렬할 수 있다
로 줄 수·단어 수를 셀 수 있다
find 로 폴더 속 파일과 폴더를 이름·종류로 찾을 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
grep 옵션 찾을 말 어디서
찾을 말이 먼저, 어디서 찾을지가 나중입니다. 이 순서는 바뀌지 않습니다.
sort 옵션 파일
파일의 줄을 정렬합니다. -r 은 순서를 거꾸로, -n 은 숫자로 정렬합니다.
wc 옵션 파일
파일 내용의 개수를 셉니다. -l은 줄, -w는 낱말, -c는 수입니다. 바이트 수는 글자 수와 다를 수 있습니다.
find 어디서 조건 동작
find 는 문장처럼 읽힙니다 — 어디서 찾고, 무엇에 맞고, 찾은 것마다 무엇을 할지.
따라 해 보기 예제를 누르면 이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
단어 파일 은 그 단어가 들어간 줄만 골라 보여 줍니다. -i 는 무시, -n 은 줄 번호 표시, -r 은 폴더 전체 검색으로, 에서 원하는 부분을 순식간에 찾습니다.
자세히 grep 은 파일을 한 줄씩 읽어 이 어디에든 들어 있는 줄을 모두 출력합니다. 그래서 을 찾으면 'concatenate' 도 걸립니다. 낱말 전체가 맞을 때만 찾으려면 -w 를 붙입니다. 패턴에 공백이나 기호가 있으면 로 감싸세요(grep "error code" app.log). -r 과 폴더를 주면 찾은 줄 앞에 파일 이름을 붙여 주어, 어느 파일에서 찾았는지 알 수 있습니다.
는 줄을 순서대로 정렬합니다. 는 바로 이웃한 같은 줄을 하나로 합치므로, 흩어진 중복을 모으려면 먼저 sort를 씁니다. -l은 줄 수를 셉니다. 다음 단원에서는 이 들을 로 이어 간단한 통계를 내 봅니다.
자세히 sort 는 글자로 비교하기 때문에 그냥 쓰면 10 이 9 보다 앞에 옵니다. 숫자는 sort -n, 거꾸로는 sort -r 을 씁니다. uniq 는 바로 이웃한 같은 줄만 합치기 때문에 거의 언제나 sort 뒤에 옵니다. wc 를 없이 쓰면 줄 수·낱말 수· 수 세 숫자를 차례로 보여 주고, -l·-w·-c 로 하나만 고릅니다.
이 파일 속의 줄을 찾는다면, find 는 폴더 속의 파일과 폴더 자체를 찾습니다. 시작한 폴더와 그 아래 모든 를 끝까지 돌며, 조건에 맞는 것의 를 한 줄에 하나씩 보여 줍니다. 골격은 find 어디서 조건 동작 입니다.
조건 없이 find . 만 치면 지금 폴더 아래의 모든 것이 나옵니다. 결과는 ./photos/cat.jpg 처럼 시작한 폴더부터 이어지는 경로라서, 그대로 다른 명령에 넘길 수 있습니다.
자세히 find 는 이름이 맞는 것만 들여다보지 않고 폴더 나무 전체를 위에서 아래로 훑습니다. 그래서 / 나 홈 폴더 전체처럼 큰 곳에서 돌리면 오래 걸리고, 읽을 이 없는 폴더마다 Permission denied 가 섞여 나옵니다 — 그 오류는 끝에 2> 을 붙여 버립니다. -maxdepth 1 을 주면 지금 폴더만 보고 하위 폴더로 내려가지 않습니다. -name 은 대소문자를 가리고( 와 readme.md 는 다릅니다) 경로가 아니라 이름만 봅니다 — 경로로 맞추려면 -path "*/src/*" 를 씁니다. grep 과 짝을 지으면 "그 낱말이 든 파일이 어디 있나"를 찾습니다: find . -name "*.js" -exec grep -l "" {} +
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
grep -rin "todo" src/
grep: 이 든 줄을 찾습니다.-r: 폴더와 모든 의 파일을 다 찾습니다.-i 무시: ·Todo·todo 가 모두 걸립니다.-n줄 번호: 찾은 줄의 번호를 함께 보여 줍니다."todo"찾을 패턴입니다. 낱말 하나면 가 없어도 되지만, 감싸는 습관이 좋습니다.src/찾을 곳: src 폴더입니다.src/app.js:12: // TODO: check the password length src/utils/date.js:3:// todo: handle time zones
찾은 것마다 파일 이름 : 줄 번호 : 그 줄 내용 순서로 나옵니다. 그 파일의 그 줄을 열어 고치면 됩니다. 맞는 줄이 없으면 은 아무것도 출력하지 않는데, 오류가 아닙니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
grep "echo" todo.sh|wc -l
이 맞는 줄을 찾고 -l 이 그 줄을 세니, 몇 번 나오는지 알게 됩니다.
sort notes.txt|head -3
줄을 먼저 정렬하고 앞 세 줄만 남깁니다 — 가나다 순으로 처음 셋입니다.
find . -name "*.txt"|wc -l
find 는 찾은 것마다 를 한 줄씩 찍으니, 줄을 세면 파일 수가 됩니다.
| 로 여러 명령을 연결할 수 있다
> 로 결과를 파일에 저장할 수 있다
>> 로 파일 끝에 수 있다
의 흐름을 바꾸는 개념을 이해한다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령 | 명령
왼쪽 이 낸 결과가 오른쪽 명령의 입력이 됩니다. 중간에 파일이 없습니다.
명령 > 파일
결과를 화면이 아니라 파일로 보냅니다. 원래 있던 내용은 지워집니다.
명령 >> 파일
같은 일이지만 지우지 않고 끝에 덧붙입니다.
명령 < 파일
파일을 의 입력으로 넣어 줍니다 — 화살표가 글이 흐르는 쪽을 가리킵니다.
명령 2> 파일
2 는 를 뜻해서, 오류를 결과에서 갈라냅니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
A | 명령B는 A가 출력한 내용을 B에게 입력으로 건넵니다. | txt에서는 ls가 목록을 만들고, grep txt가 그중 txt가 들어 있는 줄만 보여 줍니다. 먼저 왼쪽 명령만 실행해 결과를 보고, | 뒤에 다음 명령을 붙여 보세요.
자세히 모든 명령에는 (읽는 곳)과 표준 출력(쓰는 곳 — 보통 화면)이 있습니다. 는 왼쪽 명령의 출력을 오른쪽 명령의 입력에 잇고, 두 명령이 동시에 돌아서 가 만들어지는 대로 흘러갑니다. 파이프라인은 한 단계씩 만드세요. 첫 명령을 실행해 출력을 보고, 그다음에 | 와 다음 명령을 붙입니다.
> 파일 은 결과를 파일에 저장(), >> 파일 은 뒤에 , < 파일 은 파일 내용을 의 입력으로 넣습니다. 오류만 따로 저장하려면 2> 오류.txt 를 씁니다.
자세히 은 명령이 시작되기 전에 리다이렉션을 먼저 준비합니다. 그래서 data.txt > data.txt 는 파일을 망가뜨립니다. > 가 data.txt 를 먼저 비우고, sort 는 빈 파일을 읽기 때문입니다. 새 파일로 쓰세요(sort data.txt > sorted.txt). 숫자는 흐름의 이름입니다. 0 은 입력, 1 은 보통 출력, 2 는 오류라서, 2> 는 오류만, >(1> 과 같음)는 보통 출력만 파일로 보냅니다.
는 입력받은 내용을 파일에 저장하면서 화면이나 다음 에도 보냅니다. T자 배관처럼 출력이 두 갈래로 나뉜다고 생각하세요. | tee list.txt로 목록을 보면서 저장할 수 있습니다. 기존 파일에 tee -a를 씁니다.
자세히 tee 는 이 필요한 파일에 쓸 때도 흔히 씁니다. "text" | tee /somefile 은 됩니다. 하지만 sudo echo "text" > /etc/somefile 은 실패합니다. 리다이렉션(>)은 sudo 가 아니라 내 이 하기 때문입니다. 화면에 다시 보일 필요 없이 파일만 원하면 끝에 > 을 붙입니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
ls ~/Downloads | grep pdf | wc -l
ls ~/DownloadsDownloads 폴더의 목록입니다. 출력이 로 갈 때 는 한 줄에 이름 하나씩 씁니다.|파이프: 그 목록을 화면에 보여 주지 않고 다음 으로 보냅니다.grep pdfpdf 가 든 줄만 남깁니다.|두 번째 파이프: 남은 줄을 다시 넘깁니다.wc -l들어온 줄의 개수를 셉니다.7
화면에 쓰는 것은 마지막 명령뿐이고, 앞의 명령들은 출력을 넘기기만 합니다. 숫자 하나는 이름에 pdf 가 든 파일의 개수입니다. 이름 자체를 보려면 마지막 부분(| -l)을 빼고 다시 실행하세요.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
ls|sort -r|head -3
세 을 줄줄이 — 늘어놓고, 순서를 뒤집고, 앞 셋만 남깁니다. 저마다 자기 작은 일만 합니다.
cat notes.txt|wc -l>count.txt&&cat count.txt
> 가 숫자를 파일에 넣어 두고, 가 그 파일을 찍어 제대로 들어갔는지 보여 줍니다.
ls|grep txt|wc -l
먼저 좁히고 그다음에 셉니다 — "그런 게 몇 개지?"에 답하는 흔한 방법입니다.
를 만들고 값을 꺼내 쓸 수 있다
변수를 로 안전하게 감쌀 수 있다
로 간단한 산술 계산을 할 수 있다
로 결과를 값처럼 가져올 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
이름=값
내가 이름 붙인 상자에 값을 담습니다. = 양옆에는 공백을 넣지 않습니다.
"$이름"
$ 로 값을 꺼내고, 를 그대로 두어 공백이 살아 있게 합니다.
$(명령)
을 돌려 그 명령이 찍은 것을 값으로 씁니다.
$((값))
괄호가 두 겹이면 계산입니다 — 이 셈을 해 줍니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
이름=값 형태로 를 만들고, 꺼낼 때는 앞에 $ 를 붙여 $이름 으로 씁니다. 중요한 규칙은 = 양옆에 공백을 넣지 않는 것입니다 (name=리엔 은 O, name = 리엔 은 X).
자세히 변수 이름에는 영문 글자·숫자·_ 만 쓸 수 있고(한글은 안 됩니다), 숫자로 시작할 수는 없습니다. 관습적으로 내가 만든 변수는 소문자로, 다른 과 함께 쓰는 설정(·HOME)은 대문자로 씁니다. 변수는 만든 안에서만 살아 있어서, 새 을 열면 사라집니다. 모든 에서 쓰려면 그 줄을 ( 은 ~/.zshrc)에 넣으세요.
를 쓸 때는 "$name" 처럼 로 감싸는 것이 안전합니다. 값에 공백이 있어도 하나의 값으로 지켜지며, 이는 9단원에서 배울 "함정 예방"의 핵심 습관입니다.
자세히 큰따옴표 안에서도 $ 는 동작해서 "$name" 은 값을 주지만, 공백은 지키고 * 가 파일 이름으로 바뀌는 것은 막습니다. 변수 바로 뒤에 글자가 붙으면 중괄호로 이름의 끝을 알려 주세요. "${name}s" 는 값 뒤에 s 를 붙이지만, "$names" 는 names 라는 변수를 찾습니다. 작은따옴표는 변수를 아예 끕니다('$name' 은 $name 그대로).
는 계산 결과를 넣습니다. 예를 들어 $(( 3 + 4 ))는 7이 됩니다. 는 의 출력 결과를 넣습니다. today=$(date)는 date를 실행하고 그 출력을 today에 저장합니다. 괄호가 두 겹이면 계산, 한 겹이면 명령 실행으로 구분하세요.
자세히 $(( )) 안에서는 를 $ 없이 쓸 수 있고($(( count + 1 ))), +·-·*·/·%(나머지)와 괄호를 씁니다. 는 정수로만 계산해서 $(( 7 / 2 )) 는 3 입니다 — 소수점 아래는 버립니다. $( ) 는 다릅니다. 이것은 명령을 실행합니다. 둘을 함께 쓰면 files=$( | -l); "$(( files * 2 ))" 같은 줄이 됩니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
today=$(date +%F); cp notes.txt "notes-$today.txt"
today=today 라는 를 만듭니다. = 양옆에 공백이 없어야 합니다.$(date +%F)date 를 실행해 그 답을 여기에 넣습니다. +%F 는 2026-10-17 같은 모양의 날짜를 달라는 뜻입니다.;첫 의 끝 — 같은 줄에서 다음 명령을 이어 실행합니다.cp notes.txtnotes.txt 를 복사합니다 …"notes-$today.txt"… 이 새 이름으로: $today 자리에 날짜가 들어가고, 가 하나의 이름으로 지켜 줍니다.아무것도 나오지 않습니다 — 이런 명령은 성공하면 조용합니다.
복사가 되면 아무것도 출력되지 않습니다. 이제 에 notes-2026-10-17.txt 가 보이고, 내일 같은 줄을 실행하면 내일 날짜의 새 파일이 생깁니다 — 간단한 날마다 입니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
count=$(ls|wc -l)&&echo "files: $count"
가 이어 놓은 이 찍은 것을 받아 내니, 줄줄이 이은 것 전체가 값 하나가 됩니다.
echo "$HOME"|wc -c
에 담긴 값도 다른 결과와 똑같이 그대로 건넬 수 있습니다.
first=$(head -1 notes.txt)&&echo "$first"
파일의 첫 줄을 내가 지은 이름에 담아 두고 찍어 봅니다.
if / elif / else 로 조건에 따라 할 수 있다
[[ ]] 로 ·숫자·파일을 비교할 수 있다
for 로 목록을 하나씩 반복 처리할 수 있다
와 문자열 비교의 차이를 안다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
if [[ 조건 ]]; then 동작; fi
if 로 열고 fi 로 닫습니다. 조건이 동작을 할지 말지 정합니다.
for 이름 in 목록; do 동작; done
목록의 항목이 하나씩 내 이름 자리에 들어가고, 한 번씩 동작이 돌아갑니다.
while [[ 조건 ]]; do 동작; done
조건이 참인 동안 되풀이하니, 안에서 무엇인가가 그 조건을 바꿔 줘야 합니다.
case 값 in 찾을 말) 동작;; esac
값 하나를 여러 와 맞춰 봅니다. 갈래마다 ;; 로 끝내고 esac 로 전체를 닫습니다.
따라 해 보기 예제를 누르면 이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
if는 조건을 검사하고, 참이면 then 뒤의 을 실행합니다. 다른 조건도 검사하려면 elif를, 어느 조건에도 맞지 않을 때 할 일은 else를 씁니다. 마지막에는 fi로 닫습니다. if 조건; then ... fi를 ‘이 조건이 맞으면 이 일을 한다’고 읽어 보세요.
자세히 if 뒤의 조건은 사실 명령입니다. if 는 그 명령을 실행하고 를 보는데, 0 이면 참입니다. 그래서 if -q milk notes.txt; then … 은 괄호 없이도 동작합니다. then 과 fi 사이의 줄은 들여 써서 이 어디서 끝나는지 보이게 하고, 한 줄로 쓸 때는 then 앞의 ; 을 잊지 마세요.
조건 검사에는 를 권장합니다. 은 ==·!=, 숫자는 (같다)·-gt(크다)·-lt(작다)·-ge(크거나 같다)·-le(작거나 같다), 파일 존재는 -f(파일)·-d(폴더)로 확인합니다.
자세히 [[ ]] 안에서는 (그리고)·||(또는)로 검사를 잇고, ! 는 '아니다'입니다: [[ -f notes.txt && ! -d ]]. 비교할 때 망설여지면 를 로 감싸세요. 옛날 에서는 꼭 감싸야 하는데, 빈 변수가 에 구멍을 내기 때문입니다. 숫자만 다룰 때는 가 더 자연스럽습니다: if (( score >= 80 )); then …
for in 목록; do ... done 은 목록의 각 항목을 하나씩 변수에 넣어 반복합니다. 처럼 범위를 쓰거나, 파일 목록을 돌 수도 있습니다.
자세히 in 뒤의 목록은 반복이 시작되기 전에 펼쳐지므로, for f in *.txt 는 텍스트 파일마다 한 번씩 돌며 $f 에 그 이름을 담습니다. 맞는 파일이 없으면 자체로 한 번 돕니다($f 가 *.txt). 그러니 [[ -e $f ]] 로 확인하거나 을 켜세요(9단원). $() 를 돌지 마세요. 이름에 공백이 있을 때는 패턴이 더 안전합니다.
1 20은 1부터 20까지 숫자를 만듭니다. for i in $(seq 1 20); do ... done은 그 숫자를 하나씩 i에 담아 20번 반복합니다. ‘for in 목록’에서 in을 빠뜨리지 마세요. 범위가 정해져 있으면 for i in {1..20}으로도 쓸 수 있습니다.
자세히 seq 는 건너뛰며 세거나 거꾸로 셀 수도 있습니다. seq 0 5 20 은 0 5 10 15 20, seq 10 -1 1 은 거꾸로 셉니다. {1..20} 같은 에는 변수를 쓸 수 없습니다({1..$n} 은 안 됨). 끝이 변수에서 오면 $(seq 1 "$n") 이나 ((i=1; i<=n; i++)) 를 쓰세요.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
for f in *.txt; do echo "$f: $(wc -l < "$f") lines"; done
for f in *.txt이 폴더의 .txt 파일마다 한 번씩 반복합니다. 돌 때마다 f 에 파일 이름 하나가 들어 있습니다.do반복할 의 시작입니다.echo "$f: …"파일 이름 뒤에 줄 수를 붙여 출력합니다.$(wc -l < "$f")그 파일의 줄 수를 셉니다. < 로 파일을 입력으로 넣어서 가 숫자만 출력합니다.done반복의 끝 — 다음 파일로 갑니다.notes.txt: 3 lines todo.txt: 12 lines
파일마다 한 줄씩 나옵니다. 반복은 .txt 파일 개수만큼 돕니다. 하나도 없으면 *.txt 라는 글자로 한 번 돌고 wc 가 오류를 내는데, 9단원의 이 이것을 막습니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
for f in *.txt; do wc -l "$f"; done|sort -n
반복이 찍은 것은 한 줄기로 흘러나오니, -n 하나로 전부 순서를 잡습니다.
ls|grep -q txt&&echo "txt here"
-q 는 아무것도 찍지 않고 성공·실패만 알리는데, 가 보는 것이 바로 그것입니다.
if ls|grep -q todo; then echo "found"; fi
이어 놓은 이 if 의 조건이 될 수 있습니다 — 건네는 것은 글이 아니라 성공·실패입니다.
를 하고 할 수 있다
함수에 ($1)를 넘겨 활용할 수 있다
(#!/bin/bash)의 역할을 설명할 수 있다
( +x)의 개념을 이해한다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
이름() { 동작; }
묶음에 이름을 붙입니다. 중괄호가 몸통을 담고, 은 건네받은 첫 값입니다.
이름 값
내가 만든 도 다른 과 똑같이 부릅니다 — 이름이 먼저, 값이 뒤에.
bash 파일
를 에게 건넵니다. 이 없는 파일도 이렇게 돌아갑니다.
chmod +x 파일
+x 는 이 파일을 돌릴 수 있다고 표시합니다. 한 번만 해 두면 됩니다.
./파일
./ 는 "바로 여기 있는 파일"이라는 뜻입니다. 은 를 뒤지지 않기 때문입니다.
따라 해 보기 예제를 누르면 이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
이름() { 들; } 형태로 를 만들면, 자주 쓰는 명령 묶음을 이름 하나로 부를 수 있습니다. 함수 안에서는 , $2 로 넘어온 값을 받습니다.
자세히 함수는 한 뒤에 합니다. 함수 안의 $1·$2는 그 함수에 넘긴 인자입니다. 결과 글자는 등으로 출력하고 result=$(myfunc)로 받을 수 있습니다. return은 글자를 돌려주는 명령이 아닙니다. return 0은 성공, return 1 같은 0이 아닌 값은 실패를 알립니다(범위 0~255).
여러 을 hello.sh 같은 파일에 저장한 것이 입니다. 첫 줄의 를 셔뱅이라고 하며, ./hello.sh처럼 직접 실행할 때 를 쓰라고 알려 줍니다. 그래서 현재 이 zsh이어도 이 스크립트는 bash로 실행됩니다. bash hello.sh처럼 실행 을 직접 지정할 수도 있습니다.
자세히 셔뱅은 반드시 맨 첫 줄이어야 하고 정확히 #! 로 시작해야 합니다. 많은 스크립트가 대신 #!/usr/bin/env bash 를 씁니다. 가 bash 를 설치된 곳에서 찾아 주어, bash 가 /bin 에 없는 시스템에서도 됩니다. . 꼬리는 사람을 위한 표시일 뿐이고, 어떤 프로그램이 파일을 실행할지는 이름이 아니라 셔뱅이 정합니다.
만든 는 +x hello.sh 로 을 준 뒤 ./hello.sh 로 실행합니다. 스크립트나 에 넘긴 값은 (첫째), $2(둘째), (전부), $#(개수)로 받습니다.
자세히 ./ 는 '이 폴더에 있는 파일'이라는 뜻입니다. 은 에 적힌 폴더에서만 을 찾는데 는 거기에 없어서, hello.sh 만 치면 '' 가 납니다. -l 로 권한을 보면 처럼 x 가 있어야 실행됩니다. $0 은 스크립트 자신의 이름이고, 로 감싼 "$@" 는 공백이 있는 인자까지 모든 인자를 그대로 넘깁니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
backup() { cp "$1" "$1.bak" && echo "saved $1.bak"; }
backup notes.txt
backup() 이라는 를 합니다.{ … ; }함수의 몸통입니다. { 뒤의 공백과 } 앞의 ; 이 꼭 필요합니다.cp "$1" "$1.bak"첫 번째 를 이름 뒤에 .bak 을 붙여 복사합니다.&& echo …복사가 됐을 때만 메시지를 출력합니다.backup notes.txt함수를 부릅니다. 함수 안에서 $1 이 notes.txt 가 됩니다.saved notes.txt.bak
첫 줄은 함수를 정의만 해서 아무것도 출력하지 않습니다. 둘째 줄이 함수를 실행해 메시지를 출력합니다. 다른 파일 이름으로 부르면 같은 단계가 그 파일에 대해 돕니다 — 이것이 함수를 쓰는 까닭입니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
bash hello.sh|wc -c
가 찍은 것도 다른 의 결과와 똑같이 그대로 넘길 수 있습니다.
chmod +x hello.sh&&./hello.sh
돌릴 수 있게 표시하고 돌리기를 한 줄에 — 뒤는 앞이 됐을 때만 일어납니다.
bash todo.sh|head -1
가 찍은 것 중 첫 줄만 봅니다.
의 성공·실패를 ($?)로 확인할 수 있다
로 성공·실패에 따라 다음 명령을 이을 수 있다
여러 파일을 for 반복으로 처리할 수 있다
으로 정해진 시각에 자동 실행하는 개념을 안다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령 && 명령
앞 이 성공했을 때만 뒤 명령을 돌립니다.
명령 || 명령
앞 이 실패했을 때만 뒤 명령을 돌립니다 — 비상구입니다.
명령 >> 파일 2>&1
결과와 를 한 기록 파일에 함께 모읍니다.
시각 명령
의 골격입니다 — 시각 뒤에 . 에서 돌고, 이 실습 에서는 돌지 않습니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
모든 은 끝날 때 성공(0)·실패(0이 아닌 값)를 나타내는 를 남깁니다. 바로 앞 명령의 결과는 $? 로 확인하며, 명령A 명령B 는 A 가 성공했을 때만 B 를 실행합니다.
자세히 0 이 아닌 는 마다 스스로 정합니다. 예를 들어 은 맞는 줄이 없으면 1, 무언가 잘못되면 2 를 돌려줍니다. A || B 는 && 의 반대로, A 가 실패했을 때만 B 를 실행합니다( || "만들 수 없음"). 성공한 는 exit 0, 실패한 스크립트는 exit 1(또는 다른 숫자)로 끝내야, 실행한 쪽 — 사람··다른 스크립트 — 이 결과를 확인할 수 있습니다.
파일 여러 개에 같은 작업을 하려면 for 반복과 파일 조작을 결합합니다. 예를 들어 폴더의 모든 사진을 폴더로 날짜별로 복사하는 일을 몇 줄로 할 수 있습니다.
자세히 파일을 바꾸기 전에 앞에 를 붙여 실행할 내용을 먼저 보세요. 이를 라고 합니다. 백업 이름에 $(date +%F)를 넣으면 날짜별로 나눌 수 있지만, 같은 날 다시 실행하면 이름이 겹칩니다. 실행마다 따로 남기려면 시각도 넣으세요. 단계별 안내를 출력하면 진행 상황을 알기 쉽습니다.
은 정해진 시각에 을 실행하는 예약 도구입니다. crontab -e로 설정을 열고 ‘분 시 일 월 요일’ 뒤에 실행할 명령을 적습니다. 0 3 * * *는 매일 새벽 3시라는 뜻입니다. 아래 예약 줄은 에서 바로 실행하지 않고 crontab 설정에 넣습니다.
자세히 다섯 칸은 분(0–59), 시(0–23), 날짜, 월, 요일(0 = 일요일)입니다. * 는 '매번', 분 칸의 */15 는 15분마다, 요일 칸의 1-5 는 월요일부터 금요일까지입니다. cron 은 아주 짧은 로, 터미널 없이 돌기 때문에 를 쓰고 출력을 보내야 오류를 볼 수 있습니다. crontab -l 은 지금 등록된 작업을 보여 줍니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
*/15 9-18 * * 1-5 /home/you/check.sh >> /home/you/check.log 2>&1
*/15분: 15분마다(0·15·30·45분).9-18시: 9시부터 18시까지.* *날짜와 월: 언제나.1-5요일: 월요일(1)부터 금요일(5)까지./home/you/check.sh실행할 를 로 — 은 스크립트가 있는 폴더가 아니라 에서 시작합니다.>> /home/you/check.log출력을 끝에 덧붙입니다.2>&1오류도 같은 로그로 보내 나중에 읽을 수 있게 합니다.아무것도 나오지 않습니다 — 이런 명령은 성공하면 조용합니다.
이 줄은 에 치는 것이 아닙니다. crontab -e 로 저장하면 cron 이 알아서 실행합니다 — 평일 9:00 부터 18:45 까지 15분마다. 에는 아무것도 나오지 않으니, check.log 를 열어 무슨 일이 있었는지 보고, crontab -l 로 줄이 저장됐는지 확인하세요.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
mkdir -p logs&&ls>logs/list.txt&&cat logs/list.txt
세 걸음을 앞이 성공했을 때만 이어 갑니다 — 가 사고를 내지 않는 방법입니다.
bash todo.sh>out.txt2>&1&&cat out.txt
이 를 결과와 같은 파일로 보내니, 기록 하나에 전부 남습니다.
cat missing.txt||echo "no such file"
는 && 의 반대쪽입니다 — 앞이 실패했기 때문에 이 말이 나옵니다.
큰따옴표·작은따옴표·따옴표 없음의 차이를 설명할 수 있다
와 이 왜 위험한지 이해한다
로 오류에 강한 를 만들 수 있다
는 언제나 큰따옴표로 감싸는 습관을 갖는다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령 "대상"
공백이 든 이름은 안에서만 대상 하나입니다. 따옴표가 없으면 둘로 보입니다.
"$이름"
안에서도 $ 는 값을 꺼내 오지만, 값을 한 덩어리로 지켜 줍니다.
'글자'
는 "이 글자 그대로"라는 뜻입니다 — $ 도 힘을 잃습니다.
명령 -- 대상
에 오는 것은 으로 읽지 않습니다. - 로 시작하는 이름을 살려 줍니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
에 따라 가 다르게 풀립니다.
의심스러우면 큰따옴표로 감싸는 것이 기본 원칙입니다.
자세히 짧게 시험해 보면 차이가 보입니다. name="a b" 일 때 $name 은 a b(공백이 줄어듦)를, echo "$name" 은 a b 를 출력합니다. 글 안에 작은따옴표를 넣으려면 큰따옴표로 감싸세요("it's"). 큰따옴표 안에서는 $·`·"·\ 몇 개만 특별하고, 앞에 를 붙이면 지켜집니다.
는 없는 값을 먼저 공백 등으로 나누고(), 그 안의 *·?를 맞는 파일 이름으로 바꿉니다(). 예를 들어 file에 my notes.txt가 있으면 $file /는 파일 두 개로 읽을 수 있습니다. cp "$file" backup/처럼 감싸면 이름 하나로 전달됩니다.
자세히 나누는 기준은 IFS 의 글자들로, 기본은 공백·탭·입니다. 그다음 글로빙이 *·?· 를 맞는 파일 이름으로 바꾸므로, * 를 담은 변수가 갑자기 폴더의 모든 파일 이름이 될 수 있습니다. 둘 다 따옴표 없는 에서만 일어나고, 큰따옴표 안에서는 절대 일어나지 않습니다.
은 에서 실수를 빨리 발견하도록 돕습니다. 각 의 역할은 다음과 같습니다.
이 옵션들이 모든 실수를 막지는 않습니다. 로도 검사하고 실제 결과를 확인하세요.
자세히 set -euo pipefail 은 바로 다음 줄에 두어 스크립트 전체에 걸리게 하세요. shellcheck 는 로 설치합니다( install shellcheck, install shellcheck). 많은 안에서 동작해, 치는 동안 실수에 밑줄을 그어 줍니다. 경고에는 SC2086( 빠짐) 같은 번호가 있고, 번호마다 고치는 법을 설명하는 페이지가 있습니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
cp -- "$src" "$dest/"
cp: 복사합니다.--: -- 뒤는 - 로 시작하더라도 모두 이름입니다."$src"로 감싼 원본: 공백 있는 이름도 하나로 남습니다."$dest/"따옴표로 감싼 대상 폴더: 마지막 / 가 폴더여야 한다는 것을 분명히 합니다.아무것도 나오지 않습니다 — 이런 명령은 성공하면 조용합니다.
복사가 되면 아무것도 출력되지 않습니다. 따옴표가 없으면 'my report.txt' 같은 이름이 인자 두 개로 쪼개지고, -- 가 없으면 - 로 시작하는 이름(-r 등)이 으로 읽힙니다. 두 가지 안전장치가 있으면 값에 무엇이 들어 있든 정확히 이름 하나로 전달됩니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
ls *.txt|wc -l
이 별표를 먼저 채워 주니, -l 이 세는 것은 진짜 파일 이름입니다.
wc -l "report 2024.txt"|head -1
가 공백이 든 이름을 파일 하나로 지켜 줍니다. 없으면 둘로 보입니다.
grep 'e' "report 2024.txt"|wc -l
찾을 말은 로, 공백이 든 이름은 큰따옴표로 묶고 나서 셉니다.
node -v 로 설치 여부와 을 확인할 수 있다
node app.js 로 자바스크립트 파일을 실행할 수 있다
npm 으로 를 설치하고 를 실행할 수 있다
로 없이 도구를 한 번 실행할 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
node 파일
파일을 에 건네면 그대로 돌립니다.
명령 옵션
은 거의 모든 도구에서 통해서, 설치를 확인하는 가장 빠른 길입니다.
npm 동작
은 둘째 자리에 을 받습니다 — run·install·init 처럼.
npm 동작 옵션 대상
install 뒤에 설치할 이름을 적습니다. 인터넷이 연결된 실습 에서 실행할 수 있습니다.
따라 해 보기 예제를 누르면 이 실습 터미널 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
는 밖(·)에서 를 실행해 주는 ()입니다. 웹 화면을 만드는 도구, 터미널에서 쓰는 도구, , 많은 가 Node 위에서 동작합니다. 을 배운 다음으로 익혀 두면 개발 도구 설치·실행이 훨씬 수월해집니다.
자세히 Node.js 는 과 같은 (V8)을 씁니다. 다만 웹 페이지를 보여 주는 대신 파일을 읽고 쓰고, 에 연결하고, 다른 프로그램을 실행합니다. 짝수 번호 (22·24 등)은 몇 년 동안 수정을 받는 (LTS) 판이 되므로 배울 때 안전합니다. nodejs.org 에서 설치하거나 으로 설치합니다(심화 내용 참고).
-v(또는 node )로 을 확인합니다. node app.js 는 파일을 실행하고, node -e "(1+1)" 은 한 줄 를 바로 실행합니다. 파일이 없거나 문법 오류면 가 나옵니다.
자세히 node 만 치면 이 열립니다. 를 한 줄씩 바로 실행하는 대화형 (>)이고, .exit 나 로 나갑니다. 는 로 를 읽습니다. node greet.js Mina 로 실행하면 process.argv[2] 가 "Mina" 입니다. console.log 는 으로 쓰기 때문에, 도 다른 처럼 에 끼울 수 있습니다(node report.js | total).
은 다른 사람이 만든 묶음인 를 설치하고 관리합니다. 프로젝트의 package.json에는 이름·, 필요한 패키지(dependencies), 실행할 ()이 적혀 있습니다. 그 폴더에서 npm install로 패키지를 받고 start로 scripts의 start를 실행합니다. 는 없이 패키지의 명령을 실행할 때 씁니다.
자세히 npm install 은 두 가지를 만듭니다. 는 내려받은 코드입니다 — 흔히 아주 크며, 고치거나 하지 않습니다. 은 설치된 정확한 버전입니다 — 모두가 같은 것을 받도록 커밋합니다. npm ci 는 잠금 파일에 적힌 그대로만 설치해서 자동 가 씁니다. 같은 버전은 '이 버전이나 호환되는 더 새 버전'이라는 뜻입니다.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
npm install --save-dev prettier
npm 와 함께 오는 입니다.install를 내려받아 프로젝트에 더합니다.--save-devdevDependencies 에 적습니다: 개발할 때만 필요하고 앱이 돌 때는 필요 없는 것. 짧게는 -D 입니다.prettier패키지 이름 — 여기서는 를 가지런히 정리해 주는 도구 입니다.added 1 package, and audited 2 packages in 2s found 0 vulnerabilities
은 패키지를 몇 개 더했는지(패키지가 다른 패키지를 데려오기도 합니다) 알리고, 짧은 (audit)를 합니다. 이제 package.json 의 devDependencies 에 prettier 가 적혀 있고, prettier --write . 로 프로젝트에 실행할 수 있습니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
node app.js|wc -l
가 찍은 것도 그냥 글이라, 이 다른 것처럼 셀 수 있습니다.
cat package.json|grep name
파일을 읽어서 내가 보고 싶은 줄만 남깁니다.
node --version&&npm --version
확인 둘을 한 줄에 — 앞 도구가 정말 있을 때만 뒤가 돕니다.
가 개발 설치의 전제임을 설명할 수 있다
· · · 의 대표 설치 을 안다
(-g)와 일회 실행()의 차이를 구분할 수 있다
설치 후 확인 습관을 갖는다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령 옵션
에 를 물어 정말 깔렸는지 확인합니다.
command -v 명령
그 이 있으면 를 찍고, 없으면 아무것도 찍지 않습니다.
명령 동작 옵션 대상
설치 은 대개 이 골격입니다 — , , , . 에서 쓰세요.
curl 옵션 값 -o 파일
주소에서 내려받아 -o 뒤에 적은 파일에 저장합니다. 실습 에서도 인터넷 연결이 되면 실행할 수 있습니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
현대 개발은 만으로 끝나지 않습니다. 이런 가 에서 동작합니다.
10단원에서 배운 · 이 그 출발점입니다.
자세히 이 도구들은 대부분 계정이 필요합니다. 에서 한 번 로그인하면(예: firebase login) 도구가 기억합니다. 모두 에 있는 평범한 이라, 이 과정에서 배운 ··가 그대로 통합니다. AI 코딩 에이전트는 을 대신 실행해 주기도 하므로, 명령이 무엇을 하는지 아는 것이 덜 중요해지는 게 아니라 더 중요해집니다.
공식 설치 방법은 바뀔 수 있으니 항상 공식 문서를 우선하세요. 일반적인 출발점은 다음과 같습니다.
설치 후 , codex --version, firebase --version 처럼 을 확인합니다.
자세히 설치 직후 을 못 찾으면 먼저 을 새로 열어 보세요. 설치 과정에서 바뀐 가 새 터미널에 적용될 수 있습니다. 설정을 직접 다시 읽으려면 현재 에 맞는 파일을 쓰세요(zsh은 , bash는 ~/.bashrc 등). 업데이트는 설치한 방법을 따릅니다. npm 는 npm install -g firebase-tools처럼 업데이트하고, npm uninstall -g 뒤에 이름을 적어 지웁니다.
인터넷에서 받은 ( | )는 가능하면 내용을 먼저 읽고, 신뢰할 수 있는 공식 출처만 사용하세요. 는 오류가 나면 를 쓰기보다 환경을 점검하세요. 팀· 에서는 에 devDependency 로 고정해 을 맞추는 편이 안전합니다.
자세히 는 실행하기 전에 내려받아 읽어 보세요. curl -fsSL 주소 -o install.sh 로 받고, less install.sh 로 읽은 뒤, bash install.sh 로 실행합니다. -fsSL 에서 -f 는 오류면 멈추고, -s 는 조용히, -S 는 그래도 오류는 보여 주고, -L 은 바뀐 주소를 따라갑니다. 아무 영상이나 게시판의 curl | bash 줄을 붙여 넣지 말고, 의 공식 사이트에서 복사하세요.
실제로 자주 쓰는 명령 한 줄을 조각조각 나눠 봅니다. 조각마다 하는 일을 읽고, 화면에 무엇이 나오는지 확인하세요.
curl -fsSL https://claude.ai/install.sh -o install.sh
curl에서 내려받습니다.-fsSL짧은 넷을 붙인 것: 오류면 실패, 조용히, 그래도 오류는 표시, 바뀐 주소 따라가기.https://claude.ai/install.sh의 공식 주소입니다.-o install.sh바로 실행하지 않고 파일로 저장합니다.아무것도 나오지 않습니다 — 이런 명령은 성공하면 조용합니다.
내려받기가 되면 아무것도 출력되지 않습니다. less install.sh 로 읽은 뒤 install.sh 로 실행하세요. -o install.sh 대신 | bash 를 쓰면 를 보지도 못한 채 바로 실행됩니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
cat tools.md|grep -i git|head -3
읽어서 이야기가 있는 줄만 남기고(-i 는 를 가리지 않음), 그중 셋만 봅니다.
which bash&&bash --version|head -1
이 있는지 먼저 찾고, 그다음에야 를 묻습니다.
ls|sort|head -2
가장 수수한 잇기입니다 — 늘어놓고, 정렬하고, 잘라 냅니다.
-c 와 -e 로 다른 언어를 한 줄 실행할 수 있다
을 파일로 저장해 python3 파일.py 로 실행할 수 있다
(<<PY)으로 여러 줄짜리 프로그램을 에 넘길 수 있다
sed 로 파일의 텍스트를 규칙에 따라 일괄 수정할 수 있다
awk 로 표 형태 에서 을 뽑고 집계할 수 있다
이 준 를 실행하기 전에 안전하게 확인할 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
awk '{동작}' 파일
는 줄마다 내가 적은 동작을 돌립니다. 은 첫째 칸입니다.
awk '조건 {동작}' 파일
중괄호 앞에 을 두면 맞는 줄만 동작을 받습니다.
sed 's/찾을 말/값/' 파일
s 는 바꾸기입니다 — 이것을 찾아 저것으로. 빗금은 칸을 가르는 금으로 읽으세요.
python3 파일
.py 파일을 에 건네면 그대로 돌아갑니다.
python3 -c '동작'
-c 는 파일 없이 그 자리에서 한 줄을 돌립니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
하나로 모든 계산을 하려 들면 금방 벽에 부딪힙니다. 대신 쉘은 "누구를 언제 부를지" 정하는 지휘자 역할을 합니다. 수학·는 에게, 표 계산은 에게, 텍스트 일괄 수정은 에게 시키고, 쉘은 그 결과를 이어 붙입니다. 그래서 쉘을 알면 배운 적 없는 언어도 "불러서 쓸" 수 있습니다.
대부분의 언어는 "를 로 받아 바로 실행하는" 을 가지고 있습니다. 은 -c "코드", 는 -e "코드", 펄은 -e, 는 ruby -e 입니다. 계산기 대신 python3 -c "(2**10)" 을 치는 습관만 들여도 이 훨씬 강력해집니다.
이 한 번 쓰고 버릴 것이 아니라면 파일로 저장합니다. hello.py 에 를 적어 두고 hello.py 라고 치면 그대로 실행됩니다.
7단원에서 배운 을 쓰면 더 간단합니다.
실행이 끝난 뒤 를 쳐 보면 성공(0)인지 실패(1)인지 알 수 있습니다. 그래서 8단원에서 배운 대로 로 다음 을 이을 수 있습니다.
여러 줄의 를 한꺼번에 넘길 때는 을 씁니다. - <<'PY'를 입력한 뒤 다음 줄부터 코드를 적고, 마지막 줄에 PY만 적으세요. 두 표시 사이의 내용이 파이썬에 전달됩니다. -는 파일 대신 으로 코드를 읽으라는 뜻입니다. 도 이런 방식으로 여러 줄 코드를 실행합니다.
를 로 감싸면(<<'PY') 본문이 글자 그대로 넘어갑니다. 감싸지 않으면(<<PY) 본문 안의 $와 $() 을 이 먼저 바꿔치기합니다. 에는 $ 가 거의 없지만, 이나 에 $ 가 있으면 조용히 망가지므로 코드를 넘길 때는 따옴표로 감싸는 <<'PY' 가 기본입니다.
로 글자를 바꾸는 기본 모양은 입니다.
파일 자체를 고칠 때는 sed 's/찾을것/바꿀것/' 파일 처럼 씁니다. 원본을 파일.bak 으로 남기니 안전합니다( 와 의 차이는 아래 '주의'를 보세요).
는 표처럼 나뉜 텍스트를 다루는 작은 언어이자 입니다. 줄마다 공백으로 나눈 첫째 칸은 , 둘째는 $2입니다. 는 칸 수, NR은 줄 번호입니다. awk ' { 할 일 }'에서 패턴은 처리할 줄을 고르고, { }는 그 줄에 할 일을 정합니다. 패턴을 빼면 모든 줄을 처리하고, 할 일을 빼면 맞는 줄을 출력합니다. 은 읽기 전, END는 다 읽은 뒤 한 번 실행해 준비나 합계 계산에 씁니다.
으로 받아 표준출력으로 내보내는 프로그램끼리는 로 자유롭게 이을 수 있습니다. 예를 들어 sales.txt | '{print }' | -n | -3 은 한 줄로 이 일을 합니다.
awk· 는 이렇게 파이프로 잇고, 은 -c 나 으로 를 넘기는 것이 기본입니다. 이것이 이 지휘자라는 말의 진짜 의미입니다.
는 대개 이런 형태로 답을 줍니다. 그대로 붙여 넣기 전에 세 가지만 확인하세요. ① 어떤 파일을 고치는지 를 눈으로 읽는다. ② ·> 로 부분이 있는지 본다. ③ 중요한 파일이면 원본 원본.bak 으로 을 먼저 만든다. 을 읽을 줄 안다는 것은, AI 의 답을 검증할 수 있다는 뜻입니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
awk '{print $1}' sales.txt|sort|uniq -c
가 첫째 칸을 뽑고, 가 같은 줄끼리 모으고, -c 가 묶음마다 셉니다.
python3 hello.py|wc -c
은 찍고 은 셉니다 — 서로에 대해 아무것도 몰라도 됩니다.
sed 's/=/ /' config.txt|awk '{print $1}'
가 = 를 공백으로 바꿔 주니, 가 이름을 첫째 칸으로 읽을 수 있습니다.
. * + ? [ ] ^ $ 같은 기본 기호로 글자의 모양을 적을 수 있다
-E 로 에 맞는 줄을 찾고, -o 로 맞는 부분만 뽑을 수 있다
-E 와 으로 글의 순서를 바꿔 고칠 수 있다
과 의 차이, 가 grep -E 에서 숫자가 아닌 까닭을 설명할 수 있다
의 [[ 값 패턴 ]] 과 의 re 로 값을 검사할 수 있다
··에서 처음부터 쓸 수 있는 을 고를 수 있다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
grep -E '찾을 말' 파일
-E 는 더 넉넉한 문법을 켭니다. 거기서 | 는 "또는"입니다.
grep -oE '찾을 말' 파일
-o 는 줄 전체가 아니라 맞은 부분만 찍습니다.
sed -E 's/찾을 말/값/g' 파일
g 는 한 줄에서 맞는 것을 첫 번째만이 아니라 모두 바꿉니다.
[[ 값 =~ 찾을 말 ]]
는 안에서 바로 값과 를 맞춰 봅니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
010-1234-5678을 그대로 검색하면 그 번호만 찾습니다. 같은 3-4-4자리 형식의 번호를 찾으려면 -[0-9]{4}-[0-9]{4}처럼 모양을 적습니다. [0-9]는 숫자 하나, {3}은 세 번 반복이라는 뜻입니다. 이런 검색 규칙이 입니다. ······에서도 기본 기호는 비슷하며, 세부 문법은 도구마다 확인합니다.
. 은 아무 글자 하나입니다(a.c 는 abc 와 a1c). 는 괄호 안 글자 중 하나, [^abc] 는 괄호 안 글자를 뺀 하나, [a-z]·[0-9] 는 범위 안의 글자 하나입니다. 자주 쓰는 묶음은 줄여 씁니다 — 는 숫자, \w 는 낱말 글자(영문·숫자·_), \s 는 공백입니다. 대문자로 쓰면(\D \W \S) 반대가 됩니다. 도구에서는 ·[[:space:]] 같은 POSIX 이름도 씁니다.
* 는 바로 앞 글자가 0번 이상, + 는 1번 이상, ? 는 0번 또는 1번(colou?r 는 color 와 colour), 은 정확히 n번, {n,m} 은 n번에서 m번입니다. 반복 기호는 바로 앞의 글자 하나(또는 하나)에만 붙습니다. 그리고 가능한 한 길게 잡으려 합니다() — ".*" 은 첫 부터 줄의 마지막 따옴표까지 통째로 잡으므로, 따옴표 하나 안만 원하면 "[^"]*" 처럼 씁니다.
^ 는 줄의 시작, $ 는 줄의 끝입니다. ^error 는 error 로 시작하는 줄, done$ 는 done 으로 끝나는 줄, ^$ 는 빈 줄입니다. 는 낱말의 경계라서 \bart\b 는 art 는 찾지만 party 는 찾지 않습니다. 이 기호들은 글자를 차지하지 않고 "자리"만 정합니다. 대괄호 맨 앞의 ^([^0-9])는 "빼고"라는 전혀 다른 뜻이니 헷갈리지 마세요.
red|blue 는 red 또는 blue 입니다. ( ) 는 여러 글자를 하나로 묶습니다 — (ab)+ 는 ab, abab, ababab 에 맞습니다. 묶음은 찾은 글을 따로 꺼내 쓰는 데도 씁니다. 에서는 \2, 에서는 ${BASH_REMATCH[1]}, 에서는 m.group(1) 로 꺼냅니다. 그래서 2026-10-15 를 15.10.2026 으로 순서를 바꾸는 일이 한 줄로 끝납니다.
. * + ? ( ) [ ] { } ^ $ | \ 는 특별한 뜻이 있습니다. 이 글자 자체를 찾으려면 앞에 \ 를 붙입니다. 마침표는 \., 별표는 \*, 여는 괄호는 \( 입니다. 192.168.0.1 을 그대로 쓰면 . 이 "아무 글자"라서 192x168y0z1 도 맞습니다. 그리고 에서는 을 꼭 로 감싸세요. 감싸지 않으면 쉘이 * ? $ { } 를 먼저 자기 식으로 바꿔 버립니다.
과 에서 만나는 문법은 셋입니다.
도구에서는 를 쓰고, \d 를 꼭 쓰고 싶으면 grep -P()를 씁니다. ···(rg)은 처음부터 \d 를 압니다.
와 에는 ···find· 이 처음부터 있습니다. 하지만 마다 조금씩 다릅니다.
아래 "운영체제별 기본 " 표에 예를 모았습니다.
에서는 [[ $값 ]] 으로 검사합니다.
은 re 뒤에 아래 를 씁니다. 패턴은 r"+" 처럼 앞에 r 을 붙인 로 적습니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
grep -E "ERROR|WARN" app.log|wc -l
조심하세요 — 안의 | 는 에게 "또는"이고, 맨 밖의 | 가 을 잇는 기호입니다.
grep -o "user=[a-z]*" app.log|sort|uniq -c
맞은 부분만 뽑아 정렬하고, 각각 몇 번 나오는지 셉니다.
python3 regex.py|head -3
가 찍은 것 중 앞 세 줄만 봅니다.
자주 쓰는 기호와 뜻, 예, 그 예에 맞는 글입니다. 예를 누르면 아래 테스트기에 들어가서 바로 확인할 수 있어요.
| 기호 | 뜻 | 예 | 맞는 글 |
|---|---|---|---|
. |
아무 글자 1개 | abc · a1c |
|
* |
앞 글자가 0번 이상 | ac · abbc |
|
+ |
앞 글자가 1번 이상 | abc · abbc |
|
? |
앞 글자가 0번 또는 1번 | color · colour |
|
{n,m} |
n번에서 m번 반복 | 12 · 2026 |
|
^ |
줄의 시작 | error: disk full |
|
$ |
줄의 끝 | all done |
|
[abc] |
괄호 안 글자 중 하나 | a · e |
|
[^abc] |
괄호 안 글자를 뺀 하나 | x · - |
|
[a-z] |
범위 안의 글자 하나 | Q · k |
|
| |
또는 | red · blue |
|
( ) |
여러 글자를 하나로 묶기 | ab · abab |
|
\ |
기호를 () | . |
| 기호 | 같은 표현 | 뜻 | 예 |
|---|---|---|---|
\d |
[0-9] |
숫자 하나 | 2026 |
\w |
[A-Za-z0-9_] |
낱말 글자 하나(영문·숫자·_) | user_1 |
\s |
[ \t\n] |
공백 하나(스페이스·탭·줄바꿈) | a b |
\D \W \S |
[^0-9] … |
각각의 반대 — 숫자·낱말 글자·공백이 아닌 것 | abc |
\b |
\< \> |
낱말의 경계 — \bart\b 는 art 만 찾고 party 는 뺀다 | art |
[[:space:]] |
\s |
POSIX 이름 — macOS 를 포함해 grep·sed 어디서나 되는 안전한 표현 | 42 |
과 는 처음에 으로 읽어서 + ? | ( ) { } 앞에 \ 가 있어야 기능이 됩니다. -E 를 붙이면 이 되어 기호를 그대로 씁니다.
| 기능 | 기본 문법(BRE) — grep · sed | 확장 문법(ERE) — grep -E · sed -E |
|---|---|---|
| 1번 이상 | \+ |
+ |
| 0번 또는 1번 | \? |
? |
| 또는 | a\|b |
a|b |
| 묶음 | \( \) |
( ) |
| n번에서 m번 반복 | \{n,m\} |
{n,m} |
기호를 그대로 쓰는 법
grep -E
sed -E
awk
[[ =~ ]]
grep -P
vim \v
\w \s 는 기호입니다. grep -E 에서 \d 는 숫자가 아니라 글자 d 라서 를 쓰세요. \d 가 필요하면 grep -P()·· 를 씁니다. 의 grep·sed 에서는 \s 대신 가 안전합니다.
따로 설치하지 않아도 처음부터 쓸 수 있는 입니다. 탭을 눌러 내 를 고르세요.
grep -E
에 맞는 줄 찾기( 판이라 -P 는 없다)
grep -E 'ERROR|WARN' app.log
sed -E
찾아 바꾸기 — 파일을 고칠 때는 -i 뒤에 '' 가 필요
sed -E -i '' 's/[[:space:]]+$//' notes.txt
awk
패턴에 맞는 줄에서 만 출력
awk '/ERROR/ {print $1, $3}' app.log
find -E
파일 이름을 으로 찾기(-E 가 )
find -E . -regex '.*\.(jpg|png)'
perl
를 쓰는 — 처음부터 설치되어 있다
perl -pe 's/(\d+)-(\d+)/$2-$1/g' a.txt
zsh [[ =~ ]]
의 기본 에서 값 검사하기
[[ $v =~ ^[0-9]+$ ]] && echo number
python3
re — 처음 실행하면 설치 안내가 나올 수 있다
python3 -c "import re; print(re.findall(r'\d+', 'a1b22'))"
macOS 의 기본 쉘은 zsh 이고 · 는 BSD 판입니다. 와 똑같이 쓰고 싶으면 install grep gnu-sed 로 GNU 판(ggrep · gsed)을 깔 수 있어요.
grep -E · -P · -o
— -P 로 , -o 로 맞는 부분만
grep -Po '\d{4}-\d{2}-\d{2}' app.log
sed -E -i
파일을 바로 고치기 — GNU 는 \s · \+ 도 안다
sed -E -i 's/\s+$//' notes.txt
awk
열(필드)마다 조건 걸기
awk -F: '$1 ~ /^www/' /etc/passwd
find -regex
파일 를 정규식으로 찾기
find . -regextype posix-extended -regex '.*\.(php|js)'
bash [[ =~ ]]
값을 검사하고 을 로 꺼내기
[[ $s =~ ([0-9]+) ]] && echo "${BASH_REMATCH[1]}"
git grep
안에서만 빠르게 찾기
git grep -n -E 'TODO|FIXME'
python3
대부분의 에 들어 있는
python3 -c "import re; print(re.sub(r'\s+', ' ', 'a b'))"
의 grep·sed 는 GNU 판이라, 이 단원의 실습 과 똑같이 동작합니다.
findstr
의 찾기 — 은 일부만(+ ? | 가 없다)
findstr /R /N "^ERROR" app.log
Select-String
의 — 에 맞는 줄 찾기
Select-String -Path app.log -Pattern 'ERROR|WARN'
-match
맞으면 True, 묶음은 $Matches 에 들어간다
'2026-10-15' -match '^\d{4}-\d{2}-\d{2}$'
-replace
찾아 바꾸기 — \s 를 그대로 안다
(Get-Content a.txt) -replace '\s+$', '' | Set-Content a.txt
[regex]::Matches
맞는 곳을 모두 찾기
[regex]::Matches('a1b22', '\d+').Value
Where-Object
파일 이름을 정규식으로 고르기
Get-ChildItem | Where-Object Name -match '\.(jpg|png)$'
WSL · Git Bash
· 를 깔면 을 그대로
wsl grep -E 'ERROR|WARN' app.log
py
을 설치했다면 py 로 실행
py -c "import re; print(re.findall(r'\d+', 'a1b22'))"
PowerShell 은 정규식이라 \d \w \s 와 을 그대로 씁니다. 명령 프롬프트의 는 기능이 적어서 PowerShell 을 권합니다.
복사해서 바로 쓰는 입니다. 누르면 테스트기에 들어가서 어디에 맞는지 바로 보여요.
을 고치면 아래 글에서 맞는 부분이 바로 칠해집니다. 글도 마음대로 고쳐 보세요.
이 테스트기는 을 씁니다. 도구와 문법이 완전히 같지는 않습니다. 예를 들어 는 여기서 숫자이지만 -E에서는 로 바꿔야 합니다. grep -P로 옮길 때도 실제 결과를 확인하세요.
어떤 이든 자리로 읽을 수 있다 — 무엇을, 어떻게, 무엇에
의 네 가지 모양을 가릴 수 있다 — -l · --all · -la · -n 5
대상 자리에 를 쓰고, 이 먼저 채운다는 것을 안다
처음 보는 명령의 을 와 man 으로 스스로 알아낸다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
명령 옵션 대상
딱 하나만 외운다면 이 골격입니다 — 무엇을 할지, 어떻게 할지, 무엇에 할지.
명령 --help
거의 모든 이 여기서 자기 을 알려 줍니다. 처음 보는 명령을 익히는 길입니다.
명령 옵션 대상 어디로
는 원본 다음에 목적지를 받습니다. 가 둘인 모든 이 같은 뜻은 아니므로, 각 자리의 역할을 확인하세요.
명령 찾을 말
대상 자리의 * 는 이 먼저 채워 줍니다. 그래서 은 늘 진짜 파일 이름만 봅니다.
명령 옵션 | 명령 옵션
양쪽이 각자 자기 골격을 지키고, 는 결과만 건네줍니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
우리가 치는 거의 모든 줄은 ··대상 순서입니다. -la photos 는 "목록 보기(ls), 자세히 숨김까지(-la), photos 폴더"라는 뜻입니다. 명령은 늘 맨 앞에 오고, 손댈 것은 맨 뒤에 옵니다. 자리가 보이기 시작하면 긴 줄도 무섭지 않습니다 — 한 자리씩 끊어 읽으면 됩니다.
은 의 동작 방식을 정합니다. 짧은 옵션은 하이픈 하나(-l), 긴 옵션은 둘(--all)로 시작합니다. 의 -la는 -l -a를 합친 모양입니다. -n 5나 --output report.txt처럼 값을 받는 옵션도 있습니다. 우선 ‘명령 옵션 대상’ 순서로 읽되, 필요한 옵션과 묶어 쓰는 방법은 각 명령의 도움말에서 확인하세요.
대상 자리에는 파일이나 폴더의 를 적습니다. ·처럼 원본과 목적지를 받는 은 목적지를 마지막에 둡니다. 파일 이름을 고를 때 *는 0개 이상의 글자, ?는 한 글자, 는 숫자 하나에 맞습니다. 이 이 을 먼저 파일 이름으로 펼쳐 명령에 넘깁니다. 는 파일 존재 여부와 관계없이 a와 b 두 이름을 만드는 별도의 입니다.
은 기호로 이어집니다 — | 는 결과를 다음 명령에 건네고, > 는 파일에 쓰고, >> 는 파일 끝에 덧붙이고, 는 성공한 뒤에만, || 는 실패한 뒤에만, ; 는 그냥 다음을 돌립니다. 묶는 표시는 네 개뿐입니다 — "..." 는 글을 한 덩어리로, $(...) 는 명령 결과를 끼워 넣고, $((...)) 는 계산하고, [[...]] 는 조건을 검사합니다. 덩어리는 여는 말과 닫는 말이 짝입니다 — if 는 fi, for 는 done, { 는 }.
을 외울 필요는 없습니다. 이름 뒤에 를 붙이거나 man 과 이름을 치고 첫 줄을 읽으면 그 이 적혀 있습니다. 그 줄에서 대괄호 [ ] 는 "빼도 된다", ... 은 "여러 개 써도 된다"는 뜻이고, 그냥 적힌 낱말이 내가 채울 자리입니다. 또 모든 명령은 성공을 0 으로 알려 주는데, $? 로 볼 수 있습니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
ls *.txt|wc -l
대상 자리, 그다음 , 그다음 자기 자리를 가진 또 다른 — 양쪽이 같은 골격입니다.
ls --help|head -5
은 첫 줄에 자기 을 알려 주니, 그 도움말을 로 흘려보냅니다.
cat notes.txt report.txt|wc -l
대상 자리의 파일 둘이 한 줄기가 되고, 줄 세기는 둘을 합쳐 셉니다.
로 와 을 찾고, 파티션··이 무엇인지 설명한다
빈 디스크를 로 나누고, 로 하고, 로 붙인다
-h 로 남은 자리를 보고, 새 디스크에 파일을 쓰고, 안전하게 뗀다
과 으로 인터넷에서 내려받는다
로 을 설치한다 — 시스템은 , 은 안의 , 프로젝트는
로 의 을 설치하지 않고 바로 실행한다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
lsblk 대상
대상을 주면 는 그 와 그 안의 만 보입니다.
sudo mkfs.ext4 대상
대상은 전체가 아니라 입니다 — 그 안의 것은 모두 지워집니다.
sudo mount 대상 어디로
붙일 것이 먼저, 붙일 곳이 나중입니다 — , 그다음 폴더.
curl 옵션 값
-s 는 을 조용하게, -I 는 만 묻습니다. 값 자리는 입니다.
명령 동작 이름
는 골격이 같습니다 — 관리자, 할 일, . · install · install.
npx 옵션 이름 글자
는 자리에 이름을 둡니다 — --yes 같은 이 앞, 그 도구에 줄 말이 뒤입니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
는 마다 아래의 파일로 다룹니다. (list )는 그것을 나무 모양으로 보여 줍니다:
lsblk 는 보기만 하고 아무것도 바꾸지 않으므로 늘 첫 단계입니다. 이 단원을 열거나 [ 초기화]를 누를 때마다 디스크는 다시 빈 상태가 됩니다 — 마음껏 연습하세요.
은 안에서 따로 하나의 처럼 쓰는 구역입니다. 디스크 맨 앞의 파티션 테이블이 구역마다 어디서 시작해 어디서 끝나는지 적어 둡니다. 가 이것을 씁니다 — mklabel 는 비어 있는 새 테이블을 만들고, mkpart primary 100% 는 1MiB 부터 디스크 끝까지 파티션 하나를 더합니다. -s 는 "묻지 말고 하라"는 뜻입니다. 디스크를 바꾸는 일은 관리자의 일이라 앞에 를 붙입니다. 그 뒤 를 치면 아래에 sda1 이 보입니다.
갓 만든 은 아직 빈 땅이라 파일을 담지 못합니다. 은 그 위에 을 씁니다 — 파일마다 이름, 내용이 있는 자리, 을 기억하는 목록입니다. 는 의 기본 파일 시스템인 를, mkfs.vfat 는 · 도 읽는 를 만듭니다(에 알맞습니다). 포맷하면 그 파티션에 있던 것은 모두 지워집니다.
는 를 ·D: 대신 폴더에 연결해 씁니다. 이를 , 연결할 폴더를 마운트 지점이라고 합니다. / / 뒤에는 /mnt/data에 쓴 파일이 sda1에 저장됩니다. -h로 용량을 확인하세요. 새 은 소유이므로 sudo 로 쓰거나 sudo you /mnt/data로 를 바꿉니다. 다 쓴 뒤 sudo umount /mnt/data로 연결을 해제합니다.
( )은 화면 없는 웹 입니다. 브라우저 주소창에 주소를 넣으면 브라우저는 에 (HTTP 요청)을 보내고, 서버는 을 돌려줍니다 — ( 은 정상, 는 없음, ·302 는 다른 주소로 옮겨 감, 500 은 서버 오류), (내용의 종류·크기 같은 정보), 그리고 (··파일). 브라우저는 본문을 화면으로 그려 주지만, curl 은 받은 그대로 에 보여 주거나 파일로 저장합니다. 그래서 서버가 살아 있는지 확인하고, 파일을 내려받고, 를 부를 때 씁니다. 자주 쓰는 :
설치 에 자주 보이는 -fsSL 은 이 넷을 묶어 쓴 것입니다. 받은 내용은 로 다른 명령에 넘깁니다 — | 로 앞부분만, | 로 JSON 의 한 칸만. 이 는 SONUB 의 를 거쳐 진짜 인터넷과 통신하고, 라서 내려받기에 몇 초가 걸릴 수 있습니다.
은 같은 의 프로젝트를 모든 파일과 기록까지 통째로 복사합니다. 이 파일 하나를 받는다면, git clone 은 폴더 전체를 받습니다. 은 마지막 판만 받아 훨씬 빠릅니다. 받은 폴더에 로 들어가 로 둘러보세요. 이 는 라서 내려받기에 몇 초에서 몇십 초가 걸립니다.
는 글자로 쓰는 입니다. 을 찾아, 그 프로그램이 필요한 것까지 함께 내려받아 설치합니다. 시스템마다 다릅니다:
apk figlet 은 프로그램을 설치하고, apk search 는 찾고, sudo apk del 은 지웁니다.
는 에서 를 설치합니다. 먼저 프로젝트용 을 만들어 시스템의 파이썬과 구분해 쓰세요. -m venv ~/venv로 만들고 source ~/venv/bin/activate로 켭니다. 에 (venv)가 보이면 pip install로 그 안에 설치하고, 마칠 때 deactivate를 입력합니다. 이 실습에서는 생성에 약 1분이 걸립니다. venv 밖에는 pip가 없어 가 나며, 시스템 파이썬을 보호하는 환경에서는 오류가 날 수 있습니다.
은 프로젝트마다 를 설치합니다. 빈 폴더에서 npm init -y 를 치면 그 프로젝트가 필요한 것의 목록인 package.json 이 생깁니다. npm install ms 는 패키지를 에 내려받고 package.json 에 적어 두므로, 나중에 누구든 npm install 한 번으로 같은 환경을 다시 만듭니다. 프로젝트마다 node_modules 가 따로 있어서 두 프로젝트가 으로 다툴 일이 없습니다.
는 과 함께 오는 으로, 안의 을 설치하지 않고 바로 실행합니다. npx cowsay hello 를 치면 npx 는 먼저 지금 프로젝트의 /.bin 에서 cowsay 를 찾고, 없으면 에서 내려받아 (~/.npm/_npx)에 두고 실행합니다. 프로젝트에도, 시스템 전체(-g)에도 설치하지 않으므로 한 번만 쓸 도구나 새 프로젝트를 만들어 주는 도구(npx create-vite 같은)에 알맞습니다. 자주 쓰는 모양:
내려받은 패키지는 캐시에 남아 다음에는 다시 받지 않습니다. 이 는 라서 처음 내려받기에 몇십 초가 걸릴 수 있습니다.
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
lsblk|grep sda
가 모든 와 을 보이면, 이 실습 디스크 에 관한 줄만 남깁니다.
sudo mkdir -p /mnt/data&&sudo mount /dev/sda1 /mnt/data
폴더가 정말 만들어졌을 때만 를 붙입니다 — 는 "그게 됐을 때만"이라는 뜻입니다.
curl -s https://sonub.com/robots.txt|head -3
이 인터넷에서 파일을 받아 오고, -3 이 그중 앞 세 줄만 보입니다.
대부분의 에 이 있고, 패턴으로 익히면 배우고 외우고 바꿔 쓰기 쉽다는 것을 설명한다
를 한 칸씩 늘려 쓴다 — → → 할 일과 주소 → -g → -s 이름
같은 집안의 도구는 을 같은 뜻으로 쓴다는 것을 안다 — · 의 -g 는 , -y 는 묻지 않기
처음 보는 도구도 "도구 --help → --help" 순서로 패턴을 알아낸다
-fsSL 주소 | 를 조각마다 읽고, 실행하기 전에 내용을 먼저 확인한다
모든 은 정해진 골격을 지킵니다. 골격을 한 번 익히면 처음 보는 명령도 읽을 수 있습니다.
npx 이름 옵션
이름 뒤에 한 칸 — 는 거의 모든 도구가 알아듣는 사용법 묻기입니다.
npx 이름 동작 대상 옵션
할 일(), 대상(주소), (--list) 순서로 칸을 늘립니다. 앞의 칸은 그대로 둡니다.
명령 동작 옵션
집안에서 -g 는 늘 ""입니다 — install -g 는 전역에 설치, -g 는 전역 목록.
명령 동작 --help
마다 받는 것이 다르니, 하위 명령 뒤에 를 붙여 그것만의 을 봅니다.
curl -fsSL 값 | bash
받고() 넘기고(|) 실행한다() — 값 자리의 주소만 바꾸면 어느 든 같은 한 줄입니다.
따라 해 보기 예제를 누르면 명령이 실습 입력줄에 들어가요. Enter 를 눌러야 실행되고, 그 전에 고쳐 써도 돼요.
를 하나씩 통째로 외우면 끝이 없습니다. 하지만 대부분의 명령어는 정해진 을 따릅니다 — 어느 자리에 무엇을 적는지가 늘 같습니다. 자주 쓰는 는 거의 이 모양입니다: 도구 · 할 일() · 대상 · .
패턴을 알면 세 가지가 쉬워집니다. 배우기 — 새 명령도 이미 아는 모양이라 자리만 확인하면 됩니다. 외우기 — 긴 줄 대신 모양 하나와 낱말 몇 개만 기억합니다. 바꿔 쓰기 — 자리의 값만 바꾸면 내 일에 맞는 새 명령이 됩니다. 14단원 "명령의 골격"이 모든 명령의 문법이라면, 이 단원은 매일 쓰는 도구의 패턴입니다.
는 의 을 바로 실행합니다. 모양은 "npx 명령어 "입니다. 을 설치하는 로 한 칸씩 늘려 보세요 — 앞의 것은 그대로 두고 뒤에 한 칸만 더합니다:
한 줄이 길어 보여도 사실은 같은 모양에 칸을 하나씩 더한 것입니다. 그래서 외울 것은 줄이 아니라 순서입니다 — 도구, 할 일, 대상, 그리고 필요한 옵션.
긴 한 줄도 같은 방법으로 풀어 읽습니다 — npx skills add https://sonub.com -g -s infographics -- claude-code -y:
합치면 "sonub.com 에서 infographics 스킬 하나를, 모든 프로젝트의 클로드 코드에, 묻지 않고 설치"라는 뜻입니다. --agent 와 -a 처럼 옵션에는 긴 이름과 짧은 이름이 있고 둘은 같은 옵션입니다. 옵션끼리는 순서를 바꿔 적어도 뜻이 같습니다.
···yarn 처럼 를 다루는 는 한 집안이라 도 같은 뜻으로 씁니다. -g(--)는 "" — 지금 프로젝트 폴더가 아니라 전체에 둔다는 뜻입니다. npm install -g 는 firebase 을 어느 폴더에서나 쓰게 하고, … -g 는 을 모든 프로젝트가 함께 쓰게 하고, npm -g 는 전역에 깔린 것을 보입니다. -y(--yes)는 "묻지 말고 예"입니다. 거의 모든 도구에 통하는 옵션도 있습니다 — (-h)는 사용법, 은 판 번호. 하지만 짧은 옵션의 뜻은 집안마다 다를 수 있습니다. npx skills 의 -s 는 스킬 이름(--)이지만 의 -s 는 조용히(--silent)입니다. 새 도구를 쓸 때는 --help 로 그 집안의 뜻을 확인하세요.
··· 같은 큰 는 여러 가지 일을 합니다. 그래서 도구 이름 바로 뒤의 둘째 낱말()로 할 일을 고릅니다 — npm install · · git · git · npx skills · npx skills list. 하위 명령마다 받는 대상과 이 따로 있고, 하위 명령에도 가 붙습니다: 1. 도구 --help — 어떤 하위 명령이 있는지 봅니다 2. 도구 하위명령 --help — 그 하위 명령의 대상과 옵션을 봅니다 3. 대상 자리를 채우고, 옵션을 하나씩 더합니다
처음 보는 도구도 이 세 단계면 을 스스로 알아낼 수 있습니다.
·Bun·uv 같은 는 설치 방법이 거의 같은 한 줄입니다:
조각마다 읽으면 이렇습니다. curl 이 주소에서 ( 을 적어 둔 글)를 받아 옵니다. -f 는 가 오류( 등)로 답하면 오류 페이지를 넘기지 않고 실패로 끝내고, -s 는 진행 막대를 숨기고, -S 는 그래도 오류는 보이고, -L 은 옮겨 간 주소를 따라갑니다. | 는 받은 글을 다음 명령에 넘기고, bash(또는 sh)는 그 글을 명령으로 실행합니다. 그러니 이 한 줄은 "그 주소의 를 받아서 바로 실행한다"는 뜻입니다. 주소만 바꾸면 어느 도구든 같은 으로 설치합니다. 실습 에서는 SONUB 의 연습용 설치 스크립트 https://sonub.com/install/hello.sh 로 해 보세요 — hello 명령 하나만 만듭니다.
… | 는 인터넷에 있는 남의 을 에서 바로 실행합니다. 편하지만, 그 가 무엇을 하든 그대로 실행됩니다. 그래서 이 순서를 지킵니다:
은 혼자 쓰는 일이 거의 없습니다. 둘 사이에 기호를 두면 왼쪽이 찍어 낸 것이 곧바로 오른쪽으로 들어갑니다.
npx skills --help|head -5
사용법이 길면 -5 로 앞 다섯 줄만 봅니다 — 맨 앞에 그 의 이 있습니다.
npm ls -g|grep skills
-g 가 를 모두 보이면, 이 가 든 줄만 남깁니다.
curl -fsSL https://sonub.com/install/hello.sh|head -5
대신 로 넘기면 실행하지 않고 읽기만 합니다 — 을 쓰기 전의 습관입니다.
사용자에게 값을 물어보고 에 담습니다. 변수를 미리 할 필요가 없습니다.
echo "이름이 뭐예요?"# 질문을 화면에 출력read name# 입력을 받아 name 변수에 저장echo "안녕, $name!"# 받은 값을 사용read 는 사용자가 Enter 를 누를 때까지 기다렸다가 입력한 내용을 담습니다. -p 를 붙이면 질문을 같은 줄에 보여 주고(read -p "이름? " name), -s 는 비밀번호처럼 입력한 글자를 숨기며, -r 은 를 그대로 둡니다. 변수 이름을 주지 않으면 답은 $REPLY 에 들어갑니다.
대신 $PWD 로도 를 알 수 있습니다. 괄호 ( )로 감싼 명령은 별도의 에서 돌아, 그 안에서 해도 원래 위치는 바뀌지 않습니다.
echo "나는 $PWD 에 있어요"# 로 현재 사용(cd /tmp; pwd)# 서브셸 안에서만 이동 → 출력pwd# 바깥은 원래 위치 그대로서브쉘은 지금 의 복사본입니다. 그 안에서 바꾼 것(cd·새 변수)은 끝나면 사라지므로, (cd build make) 는 내 위치를 옮기지 않고 다른 폴더에서 합니다. 의 각 부분도 서브쉘에서 돌기 때문에, 파이프 뒤 while 반복 안에서 정한 변수가 끝나고 나면 비어 있습니다(4단원의 이 이 문제를 풉니다).
clear(또는 )로 화면을 정리합니다. 모르는 은 세 가지 도움말로 찾습니다: 은 help, 매뉴얼은 man, 상세 문서는 info.
clear# 화면 비우기 (Ctrl-L 과 같음)help for# 내장 명령(for 등)의 도움말man ls# 의 매뉴얼 페이지 (q 로 나감)help 는 의 내장 명령(·for·read)만 압니다. ls 같은 은 man 으로 봅니다. man 안에서는 화살표나 Space 로 움직이고, / 뒤에 낱말을 쳐서 찾고, q 로 나갑니다. 짧게 확인만 하려면 많은 명령이 로 요약을 보여 주고, type 은 그 이름이 내장 명령인지·프로그램인지·인지 알려 줍니다(type cd, type ls).
의 에서 세 개로 세 가지를 알아내 보세요: 지금 있는 폴더, 을 포함한 의 내용, 그리고 가 의 인지.
힌트 , 숨김 파일 과 ~ 를 붙인 , 그리고 type.
pwd
ls -A ~
type cd
-A 는 숨김 파일을 보여 주되 . 과 .. 은 빼서 실제 항목만 나옵니다. type cd 는 'cd is a shell builtin' 이라고 답합니다. cd 가 쉘의 일부인 까닭은, 따로 떨어진 은 자기를 실행한 쉘의 폴더를 바꿀 수 없기 때문입니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
{ } 안의 목록이나 범위를 이 여러 이름으로 펼칩니다. 예를 들어 file.txt는 file1.txt부터 file5.txt까지 다섯 이름이 됩니다. 그 이름들을 이나 에 넘겨 여러 폴더나 파일을 한 번에 만듭니다.
mkdir -p project/{src,tests,docs}# 폴더 3개를 한 번에 생성touch file{1..5}.txt# file1.txt ~ file5.txt 다섯 개 생성cp config.yaml{,.bak}# config.yaml → config.yaml.bak 트릭쉘은 을 실행하기 전에 중괄호를 먼저 펼치므로, 명령은 중괄호를 보지 못합니다. file{1..3}.txt 는 file1.txt file2.txt file3.txt 를 출력하니, 을 미리 확인하는 안전한 방법입니다. 범위는 글자로도 됩니다({a..e}). 중괄호 안에 공백을 넣으면 안 됩니다 — {a, b} 는 펼쳐지지 않습니다.
은 되돌릴 수 없습니다. -i(하나씩 확인)·-v(지운 것 표시)로 실수를 줄이고, 를 쓰면 휴지통으로 보냅니다.
rm -i old.txt# 지우기 전에 정말 지울지 물어봄rm -v *.tmp# 무엇을 지웠는지 보여줌rm -r tempDir/# 폴더와 내용 전부 삭제(주의!)가 rm 을 위험하게 만듭니다. rm *.tmp 는 괜찮지만 공백 하나가 더 들어간 rm * .tmp 는 폴더 안의 모든 파일을 지웁니다(-r 이 없으니 만 남습니다). 같은 으로 먼저 *.tmp 를 실행해 무엇이 지워질지 정확히 보세요. 은 빈 폴더만 지우므로, 비어 있어야 할 폴더라면 보다 안전한 선택입니다.
는 으로 정렬·형식을 바꿉니다. 자주 쓰는 세 가지를 익혀두면 편합니다.
ls -l# 한 줄에 하나씩, 자세히ls -t# 최근 수정순으로 정렬ls -R# 재귀적으로옵션은 합쳐 쓸 수 있습니다. ls -lt 는 최근 파일부터 자세히, ls -lS 는 크기순으로 보여 주고, -h 를 더하면 크기를 대신 K·M·G 로 보여 줍니다(ls -lhS). 큰 프로젝트에서 ls -R 은 수천 줄을 쏟아낼 수 있으니, 폴더만 보려면 find . -type d 가 읽기 쉽습니다.
project 라는 폴더를 만들고 그 안에 src·tests·docs 폴더와 빈 를 만드세요. README.md 를 docs 에 복사하고, 그 복사본의 이름을 guide.md 로 바꾼 뒤, 마지막으로 전체 구조를 보여 주세요.
힌트 중괄호로 폴더 셋을 한 줄에 만듭니다. 단계마다 로 확인하세요.
mkdir -p project/{src,tests,docs}
touch project/README.md
cp project/README.md project/docs/
mv project/docs/README.md project/docs/guide.md
ls -R project
-p 는 project 와 세 폴더를 함께 만듭니다. 폴더 안으로 복사하면 이름이 그대로라서, 로 guide.md 로 바꾸기 전까지 복사본은 docs/README.md 입니다. ls -R 은 모든 폴더와 그 내용을 보여 주어 결과를 한 번에 확인할 수 있습니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
은 으로 훨씬 강력해집니다. 검색·줄 번호·제외·개수 세기 등을 조합합니다.
grep -r "TODO" ./src# -r: 폴더 전체를 재귀 검색grep -n "error" app.log# -n: 줄 번호와 함께grep -v "debug" app.log# -v: 그 단어가 없는 줄만(반대)grep -c "error" app.log# -c: 몇 줄인지 개수만옵션은 합쳐 쓸 수 있습니다. grep -rnw "total" . 는 아래 모든 파일에서 낱말 전체가 맞는 줄을 줄 번호와 함께 찾습니다. -l 은 맞는 파일의 이름만 보여 주어 파일을 열기 전에 편합니다. -A 2 와 -B 2 는 찾은 줄의 뒤·앞 두 줄씩을 함께 보여 주어, 오류 앞뒤의 사정을 알 수 있습니다.
는 파일을 한 줄씩 읽으며 글자를 바꾸거나 줄을 골라 출력합니다. 기본적으로 원본 파일은 그대로입니다. -i를 붙이면 파일 자체가 바뀌므로, 아래 예제처럼 으로 을 남기세요.
sed 's/okay/great/g' file.txt# 모든 okay 를 great 로sed '/^#/d' file.txt# # 로 시작하는 줄 삭제sed -i.bak 's/old/new/g' file.txt# 파일 직접 수정 + .bak 백업sed -n '/error/p' log.txt# error 가 든 줄만 출력sed 는 한 번에 한 줄씩 읽어 을 적용하고 결과를 출력합니다. 파일 자체는 -i 를 줄 때만 바뀝니다. 의 g 는 그 줄의 모든 것을 바꾸라는 뜻이고, 없으면 첫 번째만 바뀝니다. 의 sed -i 는 백업 꼬리 값을 꼭 받아서(없으면 sed -i '' …) 와 다릅니다. 이런 차이는 13단원에서 더 봅니다.
는 각 줄을 공백(또는 -F 로 지정한 문자)으로 쪼개 , $2 … 다룹니다. 합계·필터·통계에 강력합니다.
echo 'a b c' | awk '{print $2}'# 두 번째 열 → bawk -F',' '{print $3}' data.csv# 쉼표로 나눠 3번째 열awk -F',' '$2 > 25' people.csv# 2번째 열이 25 초과인 줄awk '{s+=$1} END{print s}' nums.txt# 1번째 열 합계awk 는 줄마다 을 실행합니다. 앞의 ($2 > 25)이 줄을 고르고, 중괄호 부분이 그 줄로 할 일을 정합니다. 은 줄 번호, NF 는 칸 수라서 awk 'NR > 1' 은 머리 줄을 건너뜁니다. 은 마지막 줄 뒤에 한 번만 돌아 합계·평균에 딱 맞습니다. awk '{s+=$1} END {print s/NR}' 는 첫째 칸의 평균을 출력합니다.
작은 도구들을 로 이으면 강력한 처리가 됩니다. 는 앞 의 출력을 다음 명령의 로 넘깁니다.
cut -d ',' -f 1 file.csv# 쉼표 기준 첫 만sort file.txt | uniq -c# 정렬 후 중복 개수 세기find . -name "*.tmp" | xargs rm -f# 찾은 파일들을 에 넘겨 삭제find . -name "*.txt" -print0 | xargs -0 rm# 공백 있는 파일명도 안전()자주 쓰는 파이프라인은 무언가가 몇 번 나오는지 셉니다. cut -d' ' -f1 access.log | | -c | sort -rn | 는 첫째 칸에서 가장 많이 나온 값 10개를 보여 줍니다. xargs 는 입력으로 명령을 만들어 실행하는데, -n 1 을 주면 항목마다 한 번씩 돌고, find -print0 과 -0 을 함께 쓰면 공백 있는 이름도 안전하게 넘어갑니다.
find 는 이름 말고도 크기·고친 날짜·깊이로 고르고, 찾은 것마다 을 실행합니다. 조건을 여러 개 적으면 모두 맞아야 합니다.
find . -type f -size +10M# 보다 큰 파일find . -name "*.log" -mtime +30# 30일보다 오래전에 고친 find . -maxdepth 1 -type f# 로 내려가지 않고 의 파일만find . -name "*.tmp" -exec rm {} \;# 찾은 파일마다 실행({} 자리에 )-size 는 + 가 "넘는", - 가 "못 미치는"이라서 -size +10M 은 10MB 보다 큰 파일입니다(c 는 , k·M·G 는 킬로·메가·기가바이트). -mtime -7 은 7일 안에 고친 것, -mtime +30 은 30일보다 오래된 것이고, 분 단위는 -mmin 입니다. 조건 사이에는 보이지 않는 "그리고"(-a)가 있고, -o 는 "또는", ! 는 "아니다"입니다 — \( -name "*.jpg" -o -name "*.png" \) 처럼 괄호로 묶을 때는 이 가로채지 않게 \ 를 붙입니다. -exec 의 끝 \; 는 찾은 것마다 명령을 한 번씩, + 는 여럿을 모아 한 번에 돌려 더 빠릅니다. -delete 와 -exec rm 은 되돌릴 수 없으니, 먼저 같은 조건으로 결과만 보고 맞는지 확인한 뒤 동작을 붙이세요.
names.txt 에는 한 줄에 이름이 하나씩 있고, 어떤 이름은 여러 번 나옵니다. 이름마다 한 번씩, 몇 번 나왔는지와 함께, 가장 많이 나온 이름부터 출력하세요.
힌트 는 이웃한 줄만 합칩니다 — 먼저 정렬하세요. 그다음 숫자로 다시 정렬합니다.
sort names.txt | uniq -c | sort -rn
가 같은 이름을 나란히 모으고, uniq -c 가 그것을 합치며 앞에 개수를 붙이고, sort -rn 이 그 숫자로 큰 것부터 정렬합니다(-n 숫자로, -r 거꾸로).
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
<< 는 여러 줄 텍스트를 의 입력으로 통째로 넘깁니다. <<< 는 짧은 한 줄 을 입력으로 넣는 가벼운 방법입니다.
cat << EOF# EOF 까지 여러 줄을 입력으로여러 줄
텍스트
EOF# 두 EOF 사이가 내용grep "바나나" <<< "사과 바나나 포도"# <<< 로 한 줄 입력<< 뒤의 낱말은 표시일 뿐이고, EOF 는 관습이지 규칙이 아닙니다. <<'EOF' 처럼 표시를 로 감싸면 내용이 글자 그대로 들어가( 이 $HOME 그대로) 를 파일로 쓸 때 알맞습니다. > config.txt << EOF … EOF 는 여러 줄짜리 작은 파일을 빠르게 만드는 방법입니다.
출력()과 오류(stderr)는 다른 통로입니다. 2> 는 오류만, 은 오류를 출력과 같은 곳으로, /dev/null 은 "버리는 곳"입니다.
command 2> error.log# 만 파일로command > out.log 2>&1# 출력과 오류를 함께 out.log 로command > /dev/null 2>&1# 출력·오류 모두 버리기(조용히)순서가 중요합니다. > out.log 2>&1 은 두 흐름을 모두 파일로 보내지만, command 2>&1 > out.log 는 그렇지 않습니다. 2>&1 은 그 순간 보통 출력이 가리키던 곳 — 아직 화면 — 을 따라가기 때문입니다. 에서 &> out.log 는 > out.log 2>&1 의 짧은 형태입니다. 뜻을 아는 잡음을 /dev/null 로 숨기는 것은 괜찮지만, 모든 오류를 숨기면 문제를 찾기 어려워집니다.
<() 은 명령의 출력을 마치 파일인 것처럼 넘깁니다. 두 명령의 결과를 없이 바로 비교할 때 유용합니다.
diff <(ls dir1) <(ls dir2)# 두 폴더 목록을 바로 비교while read l; do echo "$l"; done < <(ls)# 안 가 밖에도 남음는 명령을 실행하고 그 출력에 /fd/63 같은 임시 파일 이름을 붙여 주어, 파일 이름만 받는 (diff··paste)도 읽을 수 있게 합니다. 와 zsh 의 기능이라 그냥 에는 없으므로, 는 로 시작해야 합니다. 두 번째 예가 중요한 까닭은 뒤의 while 반복이 에서 돌기 때문입니다. < <(…) 로 쓰면 반복이 내 에서 돌아 변수가 남습니다.
$() 은 명령의 결과를 값처럼 문장에 끼웁니다. (`)보다 를 권장합니다( 가능).
echo "여기 파일 $(ls | wc -l)개"# 파일 개수를 문장에 끼움today=$(date +%Y-%m-%d)# 오늘 날짜를 에$( ) 는 명령을 먼저 실행하고 그 출력을 그 자리에 넣되, 마지막 은 뺍니다. 결과에 공백이 있을 수 있으면 "$()" 처럼 로 감싸세요. $( "$()") 처럼 없이 겹쳐 쓸 수 있는 것이 백틱을 대신하게 된 가장 큰 까닭입니다.
의 파일 목록을 화면에 보면서 동시에 files.txt 에 저장하세요. 그다음 files.txt 끝에 'checked' 한 줄을 붙이고, files.txt 의 줄 수를 숫자만 출력하세요.
힌트 는 보여 주며 저장하고, >> 는 끝에 붙이고, < 는 에 파일을 입력으로 줍니다.
ls | tee files.txt
echo "checked" >> files.txt
wc -l < files.txt
tee 는 목록을 화면과 files.txt 에 동시에 씁니다. >> 는 덮어쓰지 않고 이어 붙입니다. wc -l < files.txt 는 파일을 으로 읽으므로 wc 가 파일 이름을 몰라 숫자만 출력합니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
안에서 값을 꺼내는 동시에 잘라내거나 바꿀 수 있습니다. 값을 가공하는 가장 강력한 도구입니다.
echo "${var/Some/A}"# 첫 번째 Some 을 A 로 echo "${var//Some/A}"# // 는 모든 Some 을 A 로 치환echo "${var:0:7}"# 0번째부터 7글자만 (부분 )echo "${#var}"# 문자열 길이${var/old/new} 는 이번 한 번만 바뀐 값을 쓰고, 변수 자체는 결과를 다시 담지 않는 한(var="${var//-/_}") 그대로입니다. 은 이 아니라 패턴이라 * 는 '아무 글자'입니다. 이런 은 다른 없이 안에서 일어나므로, 반복 안에서 를 부르는 것보다 훨씬 빠릅니다.
가 비어 있을 때 을 주거나, 를 한 번에 바꿀 수 있습니다.
echo "${foo:-기본값}"# foo 가 비었으면 "기본값"을 대신 사용: "${NAME:=손님}"# NAME 이 없으면 "손님"으로 설정하고 유지echo "${var^^}"# 모두 대문자 ( 4+)echo "${var,,}"# 모두 소문자:- 는 그 순간만 값을 채우고, := 는 변수에 저장까지 하고, :? 는 값이 없으면 내 메시지와 함께 를 멈춥니다(8단원). 콜론이 중요합니다. 콜론 없이 ${foo-x} 로 쓰면 변수가 비었을 때가 아니라 아예 없을 때만 기본값을 씁니다. ^^ 와 ,, 는 bash 4 가 필요한데 에 들어 있는 bash 는 3.2 이니, 기대기 전에 거기서 시험해 보세요.
${var#pattern}은 앞에서, ${var%}은 뒤에서 패턴과 맞는 부분을 지웁니다. #·% 하나는 가장 짧게, ##·%% 두 개는 가장 길게 지웁니다. 아래 예제에서 파일 이름과 폴더 경로를 각각 꺼내 보세요.
path="/usr/local/bin/run.sh"# 예시 경로echo "${path##*/}"# 맨 뒤 / 까지 제거 → run.sh ()echo "${path%/*}"# 맨 뒤 /이후 제거 → (dirname)echo "${path%.sh}"# . 만 제거# 는 왼쪽에서, % 는 오른쪽에서 자른다고 기억하세요(키보드에서 # 이 % 왼쪽에 있습니다). 기호가 하나면 가장 짧게, 둘이면 가장 길게 자릅니다. file=archive 이면 ${file%.*} 는 archive.tar, ${file%%.*} 는 archive 입니다. basename·dirname 도 같은 일을 하지만 매번 따로 을 띄웁니다.
괄호로 여러 값을 담고, [번호]로 하나씩, [@]로 전부 꺼냅니다. ${#array[@]} 로 개수를 셉니다.
array=(사과 바나나 포도)# 3개짜리 만들기echo "${array[0]}"# 첫 번째 → 사과 (번호는 0부터)echo "${array[@]}"# 전부 → 사과 바나나 포도echo "${#array[@]}"# 개수 → 3반복에서는 언제나 와 함께 "${array[@]}" 로 쓰세요. 항목에 공백이 있어도 하나씩 온전히 남습니다. 항목은 array+=(cherry) 로 더하고, 번호 목록은 ${!array[@]} 로 봅니다. 배열은 의 기능이라 그냥 에는 없고, zsh 는 번호를 1부터 세므로 같은 가 다르게 동작할 수 있습니다.
-A 로 만든 은 "이름 → 값" 짝으로 저장합니다(다른 언어의 딕셔너리/맵과 같음).
declare -A person# 연관 배열 person[name]="앨리스"# 이름표 name 에 값 저장echo "${person[name]}"# 꺼내기 → 앨리스for k in "${!person[@]}"; do echo "$k"; done# 모든 키 순회declare -A 는 꼭 필요합니다. 빠뜨리면 가 person 을 보통 배열로 여겨 모든 이름이 소리 없이 0 이 됩니다. 반복할 때 키의 순서는 보장되지 않으니, 순서가 중요하면 키를 정렬하세요. 연관 배열은 bash 4 이상이 필요해서 에 들어 있는 bash 에는 없습니다.
가 미리 채워 두는 들이 있습니다. 은 $(( )) 안에서 하며, 지수·나머지도 가능합니다. 소수 계산은 를 씁니다.
echo "$?"# 바로 앞 의 (0=성공)echo "$RANDOM"# 0~32767 사이 난수echo "$(( 2 ** 10 ))"# 지수 → 1024echo "scale=2; 10/3" | bc# 소수 계산 → 3.33$? 는 명령마다 바뀌므로, 나중에 쓰려면 곧바로 담아 두세요(status=$?). 그 밖에 $$ 는 의 , $0 은 이름, $SECONDS 는 쉘이 돈 시간, $LINENO 는 지금 줄 번호입니다. $RANDOM 은 게임에는 괜찮지만 비밀번호에는 안 됩니다 — 비밀스러운 값에는 rand 같은 제대로 된 생성기를 쓰세요.
는 시스템마다 동작이 조금씩 다릅니다. 는 어디서나 똑같이 동작하고, 자릿수·정렬·소수점을 정밀하게 다룹니다.
printf "안녕, %s!\n" "세계"# 자리에 값을 끼움 → 안녕, 세계!printf "%.2f\n" 3.14159# 소수 둘째 자리 → 3.14printf "%05d\n" 42# 5자리 0채움 → 00042printf 는 스스로 줄을 바꾸지 않으니 서식 끝에 \n 을 붙이세요. 자리보다 값을 더 많이 주면 서식이 되풀이되어, printf "%s\n" a b c 는 세 줄을 출력합니다 — 목록을 찍는 깔끔한 방법입니다. %-10s 는 글자를 10칸 너비에 왼쪽 정렬해 간단한 표의 칸을 맞춥니다.
file 에 report.final.pdf 가 들어 있습니다. 만으로 를 뺀 이름, 확장자만, 그리고 전체 이름을 대문자로 출력해 보세요.
힌트 % 는 오른쪽에서 자르고, ## 은 왼쪽에서 최대한 길게 자르고, ^^ 는 대문자로 만듭니다.
file="report.final.pdf"
echo "${file%.*}"
echo "${file##*.}"
echo "${file^^}"
${file%.*} 는 오른쪽에서 가장 짧은 '.무엇' 을 지워 report.final 이 됩니다. ${file##*.} 는 마지막 점까지 모두 지워 pdf 가 됩니다. ${file^^} 는 모든 글자를 대문자로 바꿉니다( 4 이상).
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
하나의 값을 여러 과 비교할 때 if 를 여러 번 쓰는 대신 case 가 깔끔합니다(다른 언어의 와 비슷).
case "$x" in# x 값에 따라 갈라짐 0) echo "영";;# 0 이면 1) echo "하나";;# 1 이면 *) echo "그 외";; esac# * 는 나머지 전부패턴마다 yes|y|Y) 처럼 | 로 여러 갈래를 적을 수 있고, 파일 이름과 같은 도 됩니다. *.jpg|*.png) 는 그림 파일 이름에 맞습니다. 처음 맞는 패턴이 이기고 나머지는 건너뛰므로, 모두 받는 *) 는 맨 끝에 두세요. ;; 는 갈래의 끝인데, 이것을 빠뜨리는 것이 case 에서 가장 흔한 실수입니다.
for 는 목록/범위를, while 은 조건이 참인 동안, until 은 조건이 거짓인 동안 반복합니다. 도 있습니다.
for ((i=1; i<=3; i++)); do echo "$i"; done# C 스타일 forwhile (( count < 3 )); do ((count++)); done# 조건이 참인 동안until (( count >= 3 )); do ((count++)); done# 조건이 거짓인 동안while 은 입력을 한 줄씩 읽을 때(while read -r line; do … done < file)와 무언가 준비될 때까지 기다릴 때 자연스럽습니다. break 는 반복을 일찍 끝내고, continue 는 다음 차례로 건너뜁니다. 끝없는 while true 반복에는 나갈 길이 필요합니다 — break, 또는 손으로 돌릴 때는 .
는 이 에 맞는지 검사합니다. 등은 파일/폴더가 존재하는지, 어떤 종류인지 확인합니다.
if [[ "$email" =~ ^[a-z]+@[a-z]+\. ]]; then echo 맞음; fi# 정규식 if [[ -f "$file" ]]; then echo "파일 있음"; fi# -f: 일반 파일인가if [[ -d "$dir" ]]; then echo "폴더 있음"; fi# -d: 폴더인가if [[ -z "$name" ]]; then echo "비었음"; fi# -z: 비어 있는가=~ 오른쪽의 패턴은 없이 쓰세요. 따옴표로 감싸면 그냥 글자가 됩니다. 괄호로 묶은 부분은 에 저장되어 조각을 꺼낼 수 있습니다. [[ $d =~ (+)-([0-9]+) ]] 뒤에는 ${BASH_REMATCH[1]} 이 첫 번째 숫자입니다. 파일 검사는 더 있습니다: -s(비어 있지 않음), -r·-w·-x(읽기·쓰기·실행 가능), -nt(더 새로움).
1부터 15까지 돌면서 3의 배수면 Fizz, 5의 배수면 Buzz, 둘 다의 배수면 , 나머지는 숫자 그대로 출력하는 을 써 보세요.
힌트 % 는 나눈 나머지이고, 나머지가 0 이면 '나누어떨어진다'는 뜻입니다. 어떤 검사를 먼저 해야 할지 생각해 보세요.
for i in {1..15}; do
if (( i % 15 == 0 )); then echo "FizzBuzz"
elif (( i % 3 == 0 )); then echo "Fizz"
elif (( i % 5 == 0 )); then echo "Buzz"
else echo "$i"
fi
done
(( i % 3 == 0 )) 은 i 가 3 으로 나누어떨어질 때 참입니다. if/elif 는 처음 참인 갈래에서 멈추므로 15 검사가 맨 앞에 와야 합니다 — 그렇지 않으면 15 는 Fizz 에서 멈춥니다. 나머지 숫자는 else 까지 가서 그대로 출력됩니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
은 안에서만 쓰는 , 는 바꿀 수 없는 를 만듭니다. declare 는 정수(-i)·소문자(-l)·대문자(-u) 같은 성질을 지정합니다.
greet() { local msg="안녕"; echo "$msg $1"; }# msg 는 함수 밖에서 안 보임readonly PI=3.14# 바꿀 수 없는 상수declare -i num=42; num+=10# 정수형 → 계산이 자동(52)declare -u up="hi"; echo "$up"# 항상 대문자 → HIlocal 이 없으면 함수 안에서 정한 변수는 모두 이라, 다른 곳의 같은 이름 변수를 덮어쓸 수 있습니다 — 찾기 어려운 입니다. 함수 안에서는 local 을 기본으로 쓰세요. readonly 는 절대 바뀌면 안 되는 값을 지키고, 바꾸려 하면 오류가 납니다. declare -p 이름 은 변수가 어떻게 됐는지 보여 주어 에 도움이 됩니다.
에 -v, -f 파일명 같은 을 받게 하는 표준 도구입니다. 글자 뒤 콜론(:)은 "값이 필요한 옵션"을 뜻합니다.
while getopts ":vf:" opt; do# v 는 값 없음, f 는 값 필요 case $opt in# 옵션별 v) verbose=true ;;# -v 면 verbose 켜기 f) file="$OPTARG" ;; esac; done# -f 의 값은 ":vf:" 맨 앞의 : 는 조용한 오류 처리를 켭니다. 모르는 옵션이면 opt 에 ?, 값이 빠지면 : 가 들어와 내 도움말을 출력할 수 있습니다. 는 짧은 옵션(-v)만 다루므로, 긴 옵션(--verbose)은 직접 읽어야 합니다. 반복이 끝나면 shift $((OPTIND - 1)) 로 옵션을 치워서 이 첫 번째 진짜 인자가 되게 합니다.
source(또는 .)는 다른 파일을 현재 에서 실행해 ·설정을 불러옵니다. 는 를 에도 전달합니다.
source ./lib/helpers.sh# 다른 파일의 함수·변수를 현재 셸로. ~/.bashrc# . 은 source 의 짧은 형태export API_KEY="abc123"# 자식 프로세스도 볼 수 있게를 그냥 실행하면 새 쉘에서 돌아서, 끝나면 그 변수와 는 사라집니다. source 는 지금 쉘에서 실행하므로, 를 고친 뒤 다시 읽을 때 씁니다. export 는 변수에 표시를 해서 이 쉘에서 실행한 이 받게 합니다 — 반대는 안 됩니다. 자식은 부모의 변수를 바꿀 수 없습니다. 같은 비밀은 공유하지 않고 에도 올리지 않는 파일에 두세요.
받은 이름마다 인사하는 greet 를 만들어 보세요. 공백이 있는 이름("Mina Kim")은 하나로 지키고, 이름을 하나도 받지 못하면 'Usage: greet NAME...' 을 출력하고 실패를 알려야 합니다.
힌트 은 개수, return 1 은 실패 알림, 로 감싼 "$@" 는 인자를 하나씩 온전히 지킵니다.
greet() {
if (( $# == 0 )); then echo "Usage: greet NAME..."; return 1; fi
local name
for name in "$@"; do echo "Hello, $name!"; done
}
greet Leo "Mina Kim"
(( $# == 0 )) 이 이름 없이 부른 경우를 잡습니다. 은 name 을 함수 안에만 둡니다. "$@" 는 Leo 와 Mina Kim 을 인자 두 개로 넘겨 두 줄이 출력됩니다 — 따옴표가 없으면 세 줄이 나옵니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
trap 은 가 (종료·오류·중단)를 받을 때 실행할 을 정합니다. 정리에 특히 유용합니다.
TMP=$(mktemp)# 안전한 임시 파일 만들기cleanup() { rm -f "$TMP"; }# 정리 trap cleanup EXIT# 스크립트가 끝나면 무조건 정리trap 'echo 중단됨; exit 1' SIGINT# 눌러도 안전하게EXIT 는 스크립트가 끝날 때마다 가 일으키는 신호 같은 사건입니다 — 정상으로 끝나든, exit 로 끝나든, set -e 때문에 멈추든. 그래서 trap 하나로 모든 출구를 덮습니다. ERR 는 명령이 실패할 때마다 돌아서 줄 번호()를 출력할 때 좋습니다. 는 겹치지 않는 이름으로 파일을 만들어, 같은 스크립트가 동시에 두 번 돌아도 서로의 임시 파일을 덮어쓰지 않습니다.
위쪽에 set 을 두면 오류에 강해집니다. -e(오류 시 중단)·-u( 안 된 금지)·-o ( 실패 감지)을 함께 씁니다. -x 는 디버깅용.
set -euo pipefail# 견고한 스크립트의 표준 첫 줄set -x# 실행되는 을 하나씩 출력()set +x# 디버깅 끄기set -e 에는 예외가 있습니다. if 조건 안, 나 || 목록 안, 결과를 검사하는 명령의 실패에서는 멈추지 않는데, 이미 그 실패를 다루고 있기 때문입니다. 실패해도 괜찮은 명령은 || true 로 허락할 수 있습니다. set -x 는 디버깅하는 부분에서만 켜야 추적이 짧게 남습니다.
뒤 & 를 붙이면 로 실행됩니다. 로 목록, wait 로 끝날 때까지 기다립니다.
sleep 5 &# 백그라운드로 실행jobs# 실행 중인 백그라운드 작업 목록wait# 모든 백그라운드 작업이 끝날 때까지 대기time sleep 1# 명령이 걸린 시간 측정& 는 를 바로 돌려주고 작업 번호와 를 출력합니다. 는 백그라운드 작업을 앞으로 데려오고, 는 돌고 있는 작업을 잠시 멈추며, bg 는 그것을 백그라운드에서 다시 돌립니다. 백그라운드 작업은 보통 을 닫으면 멈춥니다. 로그아웃 뒤에도 돌게 하려면 명령 & 이나 같은 도구를 씁니다.
실전에서 반복되는 방어 들입니다. 필수 값 확인, 존재 확인, 실패 시 즉시 종료.
: "${VAR:?VAR 가 필요합니다}"# VAR 없으면 에러 내고 종료command -v jq && echo "jq 있음"# 명령이 설치됐는지 확인cp a b || { echo 실패; exit 1; }# 실패하면 메시지 내고 종료는 도구가 있는지 어디서나 똑같이 확인하는 방법입니다. 답만 필요하면 출력은 버리세요(command -v > { "jq 를 설치하세요"; exit 1; }). 이런 검사는 맨 위에 두어, 작업 중간이 아니라 시작하자마자 분명한 메시지와 함께 실패하게 하세요. 여러 명령은 { …; } 로 묶는데, 공백과 마지막 ; 이 꼭 필요합니다.
backup.sh 를 써 보세요. 의 모든 .txt 파일을 backup-YYYY-MM-DD(오늘 날짜) 폴더로 복사하고, 복사가 실패하면 와 함께 멈추고, .txt 파일이 없으면 조용히 넘어가고, 끝에 몇 개를 복사했는지 출력합니다.
힌트 맨 위에 , 이름에는 date +%F, for 반복, 뒤에 { …; exit 1; }.
#!/bin/bash
set -euo pipefail
dest="backup-$(date +%F)"
mkdir -p "$dest"
count=0
for f in *.txt; do
[[ -e "$f" ]] || continue
cp "$f" "$dest/" || { echo "copy failed: $f" >&2; exit 1; }
count=$(( count + 1 ))
done
echo "copied $count file(s) to $dest"
date +%F 로 날마다 폴더가 하나씩 생기고, -p 는 폴더가 이미 있어도 불평하지 않습니다. [[ -e "$f" ]] || continue 는 *.txt 에 맞는 파일이 없을 때 반복을 건너뜁니다. 는 오류 메시지를 오류 흐름으로 보냅니다. ((count++)) 대신 count=$(( count + 1 )) 을 썼습니다. ((count++)) 는 count 가 0 일 때 '실패'를 돌려주어 set -e 를 멈추기 때문입니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
은 세 의 결합입니다. 각각이 어떤 사고를 막는지 알면 왜 표준이 됐는지 이해됩니다.
set -e# 이 하나라도 실패하면 즉시 중단set -u# 안 한 를 쓰면 에러(오타 방지)set -o pipefail# 중간이 실패해도 전체를 실패로-e 만으로는 파이프 중간의 실패를 놓칩니다. false | true 는 성공으로 치는데, 파이프는 보통 마지막 명령의 결과만 알리기 때문입니다. pipefail 은 어느 부분이든 실패하면 파이프 전체를 실패로 만듭니다. -u 는 $flie 같은 오타를 잡습니다. 그렇지 않으면 소리 없이 빈 값이 되어, "$dir/$flie" 가 $dir 안의 모든 것을 지우는 위험한 줄이 됩니다.
로 파일 이름 () 방식을 조절합니다. globstar 는 ** 로 , nullglob 은 매칭이 없으면 빈 값으로 처리합니다.
shopt -s globstar# ** 가 하위 폴더까지 매칭 ( 4+)for f in **/*.sh; do echo "$f"; done# 모든 하위의 . 파일shopt -s nullglob# 매칭 없으면 글자 대신 빈 값shopt -s 는 을 켜고 shopt -u 는 끕니다. shopt 만 치면 전체 목록이 나옵니다. nullglob 을 켜면 텍스트 파일이 없을 때 for f in *.txt 가 *.txt 라는 글자로 한 번 도는 대신 그냥 아무것도 하지 않습니다. dotglob 은 * 에 도 넣고, nocaseglob 은 파일 패턴에서 를 무시합니다. globstar 는 bash 4 가 필요합니다.
(내부 )는 단어를 나누는 기준입니다. 파일을 한 줄씩 안전하게 읽을 때 IFS= 와 read -r 을 함께 씁니다.
IFS=',' read -ra f <<< "a,b,c"# 쉼표로 나눠 f 에while IFS= read -r line; do# 공백· 보존하며 echo "$line"; done < file.txt# 한 줄씩 안전하게 읽기read -r 은 를 그대로 두고, IFS= 는 read 가 줄 앞뒤의 공백을 잘라 내지 않게 합니다. 파일의 마지막 줄 끝에 이 없으면 평범한 while read 반복은 그 줄을 놓치는데, read 뒤에 [[ -n $line ]] 을 붙이면 잡힙니다. IFS 는 하나에만 정하세요(IFS=',' read …) — 그래야 의 나머지에 영향을 주지 않습니다.
어떤 가 $LOGDIR/*.log 로 오래된 지웁니다. LOGDIR 가 비었거나 정해지지 않았거나 공백을 담고 있어도 안전하고, 절대 폴더를 지우지 않도록 고쳐 보세요.
힌트 ${VAR메시지} 는 값이 없으면 멈춥니다. 는 로 감싸되 * 는 따옴표 밖에 두세요.
set -u
: "${LOGDIR:?LOGDIR is not set}"
rm -f -- "$LOGDIR"/*.log
LOGDIR 가 비면 옛 줄은 rm -rf /*.log 가 됩니다. :? 는 그 대신 메시지와 함께 스크립트를 멈춥니다. 따옴표는 공백 있는 폴더 이름을 하나로 지키고, * 는 따옴표 밖에 있어서 여전히 파일과 맞춰집니다. -- 는 - 로 시작하는 이름을 막고, -r 없는 -f 는 폴더를 절대 지우지 않습니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
프로젝트마다 필요한 이 다를 수 있습니다. 으로 여러 버전을 설치·전환합니다.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash# nvm 설치(버전 번호는 공식 문서 확인)nvm install 22# Node 22 설치nvm use 22# 현재 에서 Node 22 사용node -v# 전환된 버전 확인nvm 은 Node 를 안에 설치하므로 에 가 필요 없습니다. 버전 번호(22)를 적은 파일이 있으면 누구든 그 프로젝트에서 nvm use 만 쳐서 맞는 버전을 씁니다. nvm default 22 는 새 이 시작할 버전을 정하고, nvm 는 설치된 버전을 보여 줍니다. 에서는 별도 프로젝트인 nvm-windows 가 같은 일을 합니다.
의 는 /.bin 을 에 넣어 실행합니다. 없이도 프로젝트 도구를 쓸 수 있습니다.
npm init -y# package.json 빠르게 생성npm install lodash# 의존성 추가npm install -D typescript# 개발 전용 의존성npm run build# scripts.build 실행스크립트는 서로를 부를 수 있습니다(다른 스크립트 안에서 npm run test). 로는 를 더 넘깁니다: npm run test -- --watch. start 와 test 는 run 없이도 되는 특별한 이름입니다( start, npm test). node_modules/.bin 은 npm run 동안에만 PATH 에 들어갑니다. 그래서 프로젝트에 설치한 도구는 이름만 치면 '' 여도 스크립트 안에서는 동작합니다.
는 없이 의 도구를 실행합니다. 프로젝트에 있으면 그 도구를 쓰고, 필요하면 내려받습니다. 최신 을 지정하려면 아래 예제처럼 를 붙입니다.
npx create-next-app@latest my-app# 프로젝트 예시npx prettier --write .# /원격 실행npx --yes cowsay hello# 확인 없이 일회 실행npx 는 먼저 프로젝트의 /.bin 에서 도구를 찾고, 없을 때만 로 내려받습니다. @ 와 버전을 붙이면 버전을 고정합니다(npx prettier@3 --check .). 모르는 패키지를 npx 로 실행하면 인터넷의 를 내 컴퓨터에서 돌리는 것이니 이름을 정확히 확인하세요 — 이름이 비슷한 가짜 패키지가 있습니다.
hello-npm 이라는 새 폴더를 만들고, , 'Hello from ' 을 출력하는 hello.js, 그리고 그것을 실행하는 npm hello 를 만드세요. 그다음 스크립트를 실행하세요.
힌트 npm init -y 가 package.json 을 만들고, npm pkg set 으로 없이 스크립트를 더할 수 있습니다.
mkdir hello-npm && cd hello-npm
npm init -y
echo "console.log('Hello from npm')" > hello.js
npm pkg set scripts.hello="node hello.js"
npm run hello
npm init -y 는 으로 package.json 을 씁니다. … > hello.js 가 을 만듭니다. npm pkg set scripts.hello=… 는 package.json 에 스크립트를 더합니다(파일을 직접 고쳐도 됩니다). hello 는 실행할 을 보여 준 뒤 Hello from npm 을 출력합니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
공식 또는 로 올립니다. 설치 직후 으로 확인하세요.
curl -fsSL https://claude.ai/install.sh | bash# ()curl -fsSL https://chatgpt.com/codex/install.sh | sh# npm install -g @xai-official/grok# (npm 대안 예시)claude --version && codex --version# 설치 확인(예시)마다 프로젝트 안의 파일에서 지시를 읽습니다(클로드 코드는 , Codex 와 많은 는 ). 그래서 프로젝트의 을 한 번만 알려 주면 됩니다. 허락하지 않으면 명령을 실행하거나 파일을 바꾸기 전에 묻는데, 실행하려는 명령을 읽어 보세요 — 이 과정의 명령이 바로 그때 보게 될 것입니다. 이런 도구는 빨리 바뀌니 버전을 확인하고 자주 업데이트하세요.
··에 쓰는 와, 빠른 도 자주 함께 설치합니다.
npm install -g firebase-tools# Firebase CLIfirebase login# 로 로그인firebase projects:list# 프로젝트 목록npm install -g pnpm# pnpm firebase init 은 질문을 하며 firebase.json 을 씁니다. firebase deploy 는 프로젝트를 올리고, firebase :start 는 시험용으로 서비스를 에서 돌립니다. 자동 는 브라우저로 로그인할 수 없어서, 대신 에 둔 를 씁니다. pnpm 은 마다 사본 하나를 여러 프로젝트가 함께 써서 를 아낍니다.
는 이 을 찾는 폴더 목록입니다. 설치했는데도 을 못 찾으면, 설치된 폴더가 PATH에 들어 있는지 확인하세요. which로 위치를 보고, 을 쓴다면 현재 쉘에서 nvm이 불러와졌는지도 살펴봅니다.
which node npm# 실행 파일 위치echo "$PATH"# 검색 경로 확인npm config get prefix# command -v firebase || echo "not found"# 설치 여부 검사PATH 는 : 로 나눈 폴더 목록이고 왼쪽부터 찾아 처음 찾은 것이 이깁니다. 그래서 가 두 번 설치되면 서로를 가릴 수 있는데, which -a node 가 모두 보여 줍니다. 폴더를 더하려면 나 ~/.bashrc 에 PATH="$HOME/./bin:$PATH" 를 넣고 새 을 여세요. install -g 의 오류는 npm 이 시스템 폴더에 쓰려 한다는 뜻으로, nvm 을 쓰거나 npm 의 를 로 옮기면 해결됩니다.
·· 이 설치돼 있는지 확인하는 짧은 을 써 보세요. 찾은 것은 을, 없는 것은 'missing: 이름' 을 출력합니다.
힌트 이름 은 그 이름이 에 있을 때만 성공합니다. 출력은 로 보내세요 — 만 중요합니다.
for tool in node npm git; do
if command -v "$tool" >/dev/null; then
echo "$tool $("$tool" --version)"
else
echo "missing: $tool"
fi
done
반복은 이름마다 한 번씩 돕니다. command -v 가 두 갈래 중 하나를 고릅니다. $("$tool" ) 은 도구 자체를 실행해 버전을 얻습니다. git 은 'git version 2.x' 를, node 는 v22.11.0 처럼 앞에 v 를 붙인 번호를, npm 은 번호만 출력합니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
거의 모든 언어가 "를 로 받아 즉시 실행"하는 을 가집니다. 옵션 글자만 다를 뿐 쓰는 법은 똑같습니다.
python3 -c "import sys; print(sys.version)"# 한 줄node -e "console.log(1 + 1)"# 한 줄perl -e 'print "hello\n"'# 펄 한 줄ruby -e 'puts (1..5).to_a'# 한 줄php -r 'echo PHP_VERSION;'# 는 -r에게 수정을 부탁하면 거의 이 형태로 답이 옵니다. 파일을 읽어 을 바꿔 다시 쓰는 조각을 으로 넘기는 방식으로, 로 "바꿀 대상이 정말 있는지" 먼저 확인하는 것이 핵심입니다.
python3 - <<'PY'# 여기서부터 PY 까지가 파이썬 p = "src/app.py"# 고칠 파일 s = open(p, encoding="utf-8").read()# 통째로 읽기old = "before text"# 찾을 문자열(이 가 없으면 )new = "after text"# 바꿀 문자열assert old in s# 바꿀 대상이 없으면 여기서 멈춘다(가장 중요)s = s.replace(old, new)# open(p, "w", encoding="utf-8").write(s)# 다시 쓰기PY# 히어독 끝 — 줄 맨 앞에 정확히안에서 여러 줄짜리 설정·문서를 만들 때도 이 가장 깔끔합니다. 태그를 감싸지 않으면 $가 그 자리에서 채워집니다.
cat <<EOF > .env# 태그를 안 감싸면 변수가 채워진다PORT=$PORT# $PORT 가 실제 값으로 바뀌어 저장EOF# 여기서 끝cat <<'EOF' > template.txt# 감싸면 $PORT 가 bash <<< "echo one-liner"# 으로 한 줄만 넘기기주소(줄 번호·)를 앞에 붙이면 원하는 줄만 고칩니다. -i 로 파일을 직접 고칠 때는 처럼 를 붙이세요 — 이 남을 뿐 아니라 와 에서 똑같이 동작합니다.
sed -n '10,20p' log.txt# 10~20번째 줄만 출력sed '/^#/d' config.txt# # 로 시작하는 줄 삭제sed -i.bak 's/3000/8080/' config.txt# 백업(.bak)을 남기고 파일 수정sed -E 's/([a-z]+)@([a-z.]+)/\2 \/ \1/' mail.txt# 으로 순서 바꾸기sed 's/error/ERROR/gI' log.txt# 무시하고 모두 printf 'appended\n' >> notes.txt# 마지막 줄 뒤에 (어디서나 통하는 방법)의 진가는 집계와 에서 드러납니다. 표를 읽어 항목별로 묶고 보기 좋게 출력하는 일이 한 줄로 끝납니다.
awk '{sum[$1] += $2} END {for (k in sum) printf "%-10s %5d\n", k, sum[k]}' sales.txt# 항목별 합계를 표로 출력awk -F, '{print $2}' data.csv# 는 -F, 로 쉼표 구분awk 'NF > 0' notes.txt# 빈 줄 제거(만 쓰면 그 줄을 출력)awk '{n = split($0, a, "/"); print a[n]}' paths.txt# 에서 파일명만awk 'NR == FNR {m[$1] = $2; next} $1 in m {print $1, m[$1], $2}' a.txt b.txt# 두 파일 joinawk 'BEGIN {printf "%.2f\n", 22 / 7}'# 만 쓰면 계산기은 로, "찾은 결과마다 실행"은 로 처리합니다. 두 도구를 알면 로 이을 수 있는 범위가 크게 넓어집니다.
curl -s https://api.example.com/u | jq '.name'# JSON 에서 필드 하나jq -r '.items[] | .id' data.json# 을 줄 단위로 펼치기(-r 은 제거)ls *.txt | xargs wc -l# 찾은 파일마다 명령 실행grep -rlZ TODO . | xargs -0 sed -i.bak 's/TODO/DONE/g'# + 일괄 수정(-Z· 으로 공백 파일명까지 안전하게, 도 남긴다)1부터 100까지의 합을 두 번 출력해 보세요. 한 번은 로 넣은 짧은 으로, 한 번은 와 로.
힌트 - 는 에서 프로그램을 읽고, awk 는 한 칸을 더해 에서 합계를 출력할 수 있습니다.
python3 - <<'PY'
print(sum(range(1, 101)))
PY
seq 1 100 | awk '{s+=$1} END {print s}'
python3 - 는 <<'PY' 와 PY 사이의 를 실행합니다. PY 를 감싼 가 이 그 안을 건드리지 못하게 합니다. seq 1 100 은 한 줄에 숫자 하나씩 쓰고, awk 가 그것을 s 에 더해 끝에 한 번 출력합니다. 둘 다 5050 을 출력합니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
* 와 + 는 가능한 한 길게 잡습니다(). 뒤에 ? 를 붙이면(*? · +?) 가능한 한 짧게 잡습니다() — 이것은 문법( -P · )에서만 됩니다. 기본·에서는 [^"]* 처럼 "그 글자가 아닌 것"으로 범위를 좁힙니다.
echo '<b>a</b><b>b</b>' | grep -Po '<b>.*</b>'# 탐욕적: 처음 <b> 부터 마지막 </b> 까지 한 덩어리echo '<b>a</b><b>b</b>' | grep -Po '<b>.*?</b>'# 게으른 매칭: <b>a</b> 와 <b>b</b> 를 따로grep -Eo '"[^"]*"' data.json# 확장 문법에서는 "가 아닌 글자"로 좁힌다grep -Po 'id=\K\d+' app.log# — 앞부분은 확인만 하고 숫자만 출력python3 -c "import re; print(re.findall(r'\d+(?=ms)', 'took 2300ms'))"# 전방 탐색 (?=…) — ms 바로 앞의 숫자만( ) 로 잡은 글을 안에서 로 다시 부르면 "같은 글이 또 나오는 곳"을 찾을 수 있습니다. 실수로 두 번 친 낱말을 찾거나 고칠 때 씁니다.
grep -Ew '([a-z]+) \1' notes.txt# 연달아 두 번 나온 낱말(the the) 찾기sed -E 's/\b([a-z]+) \1\b/\1/g' notes.txt# 두 번 친 낱말을 하나로grep -E '^(.)(.).?\2\1$' words.txt# 앞뒤가 같은 4~5글자 낱말(level · noon)sed -E 's/(.*)=(.*)/\2=\1/' config.txt# key=value 의 앞뒤 바꾸기같은 일을 마다 어떻게 하는지 나란히 비교해 보세요. · 는 · 를, 는 의 과 -replace 를 씁니다.
grep -rn -E 'TODO|FIXME' .# 리눅스·macOS: 폴더 안 모든 파일에서 찾기Select-String -Path *.txt -Pattern 'TODO|FIXME'# 윈도우 PowerShell: 같은 일sed -i.bak -E 's/[[:space:]]+$//' notes.txt# 리눅스·macOS 공통: 줄 끝 공백 지우기( .bak 을 남긴다)(Get-Content notes.txt) -replace '\s+$', '' | Set-Content notes.txt# 윈도우 PowerShell: 같은 일findstr /R /C:"^[0-9][0-9]*$" numbers.txt# 윈도우 : 숫자만 있는 줄(+ 가 없어 [0-9]* 로)(rg)은 보다 빠르고, 를 그대로 알며, 에 적힌 파일을 알아서 건너뜁니다( install ripgrep · install ripgrep). 은 ·에 처음부터 있는 의 원조이고, 은 의 와 기록을 으로 찾습니다.
rg -n 'TODO|FIXME'# 아래 전부, 줄 번호와 함께rg -o '\d{4}-\d{2}-\d{2}' -g '*.log'# .log 파일에서 날짜만perl -pe 's/(\d+)-(\d+)/$2-$1/g' a.txt# 펄: 12-34 → 34-12perl -pi -e 's/foo/bar/g' *.txt# 펄: 여러 파일을 바로 고치기git log --grep='fix.*login' -i --oneline# 메시지를 정규식으로 찾기git log -G 'apiKey' --oneline# 코드 변경 내용을 정규식으로 찾기의 re 는 문법이라 \w \s, , 까지 모두 됩니다. 은 r"…" 로 쓰는 것이 기본입니다 — 그냥 "" 라고 쓰면 백스페이스 글자로 바뀝니다.
import re# 불러오기re.search(r"\d+", "a12b").group()# 처음 맞는 것 하나 → "12"re.findall(r"\d+", "a12b345")# 맞는 것 모두 → ["12", "345"]re.sub(r"\s+", " ", "a b")# 바꾸기 → "a b"re.split(r"[,;]\s*", "a, b;c")# 정규식으로 자르기 → ["a", "b", "c"]m = re.match(r"(?P<y>\d{4})-(?P<m>\d{2})", "2026-10")# 이름 붙인 묶음 — m["y"] 는 "2026"pat = re.compile(r"error", re.I)# 미리 만들어 두기, re.I 는 무시는 을 씁니다. // 은 줄 전체를, $3 ~ /패턴/ 은 그 열만 검사하고, 로 바꿉니다. -F 에 을 주면 여러 로 한꺼번에 자를 수 있습니다.
awk '/ERROR|WARN/' app.log# -E 와 같은 일awk '$4 ~ /^user=a/' app.log# 4이 user=a 로 시작하는 줄awk '$3 !~ /INFO/ {print $3, $4}' app.log# INFO 가 아닌 줄의 3·4번째 열awk '{gsub(/[0-9]+ms/, "N ms"); print}' app.log# 줄 안의 2300ms 같은 글을 모두 바꾸기awk -F'[=: ]+' '{print $2}' config.txt# = · : · 공백 여러 개를 모두 구분자로contacts.txt 의 줄들 사이에 이메일 주소가 섞여 있습니다. 모든 주소를 한 번씩, 정렬해서, 주소만 출력해 보세요.
힌트 -o 는 맞는 부분만 출력하고, -E 는 + 와 {2,} 를 쓰게 해 주며, -u 는 중복을 없앱니다.
grep -oE '[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}' contacts.txt | sort -u
은 글자·숫자·._%+-(이름), @, , 점, 두 글자 이상의 글자 순서입니다. -o 는 한 줄에 여러 개가 있어도 찾은 것마다 한 줄씩 출력합니다. 실제 이메일 규칙은 더 복잡하지만, 찾기에는 이 패턴으로 충분합니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
은 보통 바로 뒤에 서지만, 도구()는 대상 뒤에 와도 받아 주고 BSD 도구()는 받지 않습니다. 그래서 명령·옵션·대상 순서가 어디서나 통하는 습관입니다. 에 오는 것은 모두 대상으로만 읽혀서, 빗금으로 시작하는 이름을 살려 줍니다.
ls -l notes.txt# 어디서나 통하는 순서ls notes.txt -l# 리눅스에서는 되고 macOS 에서는 안 된다rm -- -weird.txt# 빗금으로 시작하는 이름의 파일 지우기grep -- -v notes.txt# 옵션이 아니라 "-v" 라는 글자를 찾기man 이나 의 첫 줄이 바로 그 의 이고, 적는 방식이 모두 같습니다. 대괄호 [ ] 는 빼도 되는 것, ... 은 그 자리를 여러 번 써도 되는 것, 막대 | 는 둘 중 하나를 고르는 것이고, 대문자나 기울인 낱말이 내가 채울 자리입니다. 이 한 줄만 읽으면 써 본 적 없는 명령도 부를 수 있습니다.
ls --help | head -5# 첫 몇 줄에 패턴이 있다man ls# 설명서 전체 — q 로 나온다man -k copy# 하는 일로 명령을 찾기type cd# 이 이름이 인가 인가 인가모든 은 를 남기고 끝납니다 — 0 은 성공, 그 밖의 값은 실패입니다. $? 에는 바로 앞 명령의 가 들어 있고, 가 보는 것이 정확히 이 값입니다. 많은 명령에 "조용히" 이 있어서 출력 없이 코드만 쓸 수도 있습니다.
ls notes.txt; echo $?# 성공하면 0 이 나온다ls missing.txt; echo $?# 실패하면 0 이 아닌 값이 나온다grep -q echo todo.sh && echo found# -q 는 아무것도 찍지 않고 코드만 남긴다true; echo $?# true 는 늘 성공, false 는 늘 실패du 는 아직 배우지 않은 입니다. 로 을 알아낸 뒤, 다운로드 폴더에서 자리를 가장 많이 쓰는 다섯 항목을 큰 것이 뒤에 오도록 뽑아 보세요.
힌트 --help 의 첫 줄이 패턴입니다. -s 는 대상마다 합계 하나, -h 는 사람이 읽는 단위, -h 는 그 단위를 이해하고 정렬합니다.
du --help | head -20
du -sh ~/Downloads
du -sh ~/Downloads/* | sort -h | tail -5
du --help 를 보면 패턴이 du []... [FILE]... 입니다 — 두 자리가 모두 선택이고 여러 번 써도 된다는 뜻입니다. 그래서 - 를 옵션 자리에, ~/Downloads/* 를 대상 자리에 넣고, 그 결과를 sort -h 로 넘겨 -5 로 끝 다섯 줄만 봅니다. du 를 외운 적은 없고 패턴만으로 쓴 것입니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
가 나무를 그려 준다면, 그 안을 들여다보는 이 셋 더 있습니다. -l 은 을 단위로 보이고, 는 종류와 를 보입니다 — UUID 는 바뀌지 않는 일련번호로, 를 더하면 바뀔 수 있는 같은 이름과 다릅니다. 는 같은 테이블을 parted 의 말로 보입니다. 모두 읽기만 합니다.
sudo fdisk -l /dev/sda# 파티션 테이블을 섹터 단위로sudo blkid# 파티션마다 파일 시스템 종류와 UUIDsudo parted -s /dev/sda print# 같은 테이블을 parted 가 보는 대로cat /proc/partitions# 이 직접 아는 목록연습하려고 남는 가 꼭 있어야 하는 것은 아닙니다. 는 보통 파일을 디스크처럼 쓰게 해 줍니다 — 원하는 크기의 파일을 만들고, 하고, -o 로 합니다. 의 나 USB 설치 이미지가 바로 이렇게 동작합니다.
truncate -s 16M usb.img# 비어 있는 파일mkfs.vfat usb.img# 처럼 포맷sudo mkdir -p /mnt/usb && sudo mount -o loop usb.img /mnt/usb# 파일을 디스크처럼 마운트df -h /mnt/usb# 사실은 파일인 16MB "디스크"갓 한 의 은 입니다. 으로 을 내 것으로 바꾸면 없이 씁니다. 또 마운트는 컴퓨터를 다시 켤 때까지만 갑니다. 실제 에서는 에 한 줄을 더해 켤 때마다 마운트되게 하고, 이름보다 의 를 쓰는 편이 안전합니다. 다시 켜기 전에 -a 로 그 줄을 시험하세요 — fstab 이 틀리면 서버가 켜지지 않을 수 있습니다.
sudo chown you /mnt/data# 이제 마운트 지점의 주인은 나echo "mine" > /mnt/data/mine.txt# 이제 sudo 가 필요 없습니다echo "/dev/sda1 /mnt/data ext4 defaults 0 2" | sudo tee -a /etc/fstab# 켤 때마다 마운트(실제 서버에서는 UUID=… 를 쓰세요)sudo umount /mnt/data && sudo mount -a && df -h /mnt/data# fstab 의 줄이 되는지 확인는 모두 같은 몇 가지 — 찾기·설치·목록·지우기 — 를 조금씩 다른 말로 합니다. · 는 시스템 전체에 설치하므로 가 필요하고, · 은 나 프로젝트 폴더 안에 설치하므로 필요 없습니다. pip freeze 와 은 어디서든 같은 환경을 다시 만드는 조리법입니다.
apk search htop# 이름으로 패키지 찾기sudo apk del figlet# 설치한 다시 지우기pip freeze > requirements.txt# 이 venv 의 패키지 적어 두기npm ls# 이 프로젝트가 쓰는 패키지지금까지는 받아 오기()만 했습니다. 에 무언가를 보낼 때는 -X 로 방식을 바꾸고, -d 뒤에 보낼 내용을, -H 로 (내용의 종류·접근 )를 붙입니다. -v 는 오가는 과 을 모두 보여 주므로, 왜 안 되는지 찾을 때 씁니다. 가 느리거나 잠깐 끊길 때를 대비해 --max-time 으로 기다릴 시간을 정하고 --retry 로 다시 시도합니다. 에서는 -f 를 붙여 실패를 로 알게 하세요. 토큰 같은 비밀은 에 그대로 쓰지 말고 에 두세요.
curl -X POST -H "Content-Type: application/json" -d '{"name":"you"}' https://httpbin.org/post# 을 보내기 — 받은 쪽이 무엇을 받았는지 돌려줍니다curl -v -o /dev/null https://sonub.com/robots.txt# 오가는 요청·응답 헤더를 모두 보기(> 는 보낸 것, < 는 받은 것)curl -fsS --max-time 10 --retry 3 -o /dev/null https://sonub.com/up && echo OK# 10초 안에, 실패하면 세 번까지 다시 — 서버 확인 스크립트의 기본curl -H "Authorization: Bearer $TOKEN" https://api.github.com/user# 접근 토큰은 환경 변수로(없으면 401 로 답합니다)실습 를 반으로 나누세요. 앞쪽 절반은 로, 뒤쪽 절반은 (vfat)로 하고, / 와 /mnt/share 에 한 뒤 -h 로 둘을 비교해 보세요.
힌트 하나로 테이블과 둘을 만들 수 있습니다 — ~50% 와 50%~100%. 그다음 와 mkfs.vfat, 마운트 지점 둘, 마운트 둘입니다.
sudo parted -s /dev/sda mklabel gpt mkpart data ext4 1MiB 50% mkpart share fat32 50% 100%
lsblk /dev/sda
sudo mkfs.ext4 /dev/sda1
sudo mkfs.vfat /dev/sda2
sudo mkdir -p /mnt/data /mnt/share
sudo mount /dev/sda1 /mnt/data
sudo mount /dev/sda2 /mnt/share
df -h /mnt/data /mnt/share
gpt 는 요즘 쓰는 파티션 테이블이고, gpt 테이블에서 mkpart 는 이름(data, share)을 먼저 받습니다. 두 파티션은 sda1 과 sda2 가 되고, 각자 자기 을 갖습니다. df -h 는 둘을 크기와 함께 보입니다 — FAT 는 자기 몫으로 남기는 자리가 적어서 남은 자리가 ext4 와 조금 다르게 보입니다.
이 과제는 내 컴퓨터가 아니라 실습 터미널에서 하세요 — 디스크를 지우고 다시 만듭니다. 먼저 [세션 초기화]를 눌러 디스크를 비우세요.
짧은 은 글자가 하나라 서로 겹칩니다. -v 는 · 에서는 (), 에서는 "맞지 않는 줄만"(invert), ·ssh 에서는 "자세히"(verbose)입니다. -s 도 에서는 스킬 이름, curl 에서는 조용히입니다. 긴 옵션(--version · --verbose · --silent)은 뜻이 이름에 적혀 있어 헷갈리지 않으니, 에는 긴 옵션을 쓰면 나중에 읽기 쉽습니다.
node -v# node 에서 -v 는 판 번호grep -v '#' patterns.txt# grep 에서 -v 는 # 이 든 줄을 빼고curl -v https://sonub.com -o /dev/null# curl 에서 -v 는 주고받는 내용을 자세히npx skills add --help | grep -- "-s,"# 이 집안에서 -s 가 무슨 뜻인지 찾기도 을 받습니다. … | 에서는 가 으로 들어가므로 bash -s 에 옵션을 적습니다 — -s 는 "스크립트를 입력에서 읽어라", -- 는 "여기부터는 스크립트에 줄 말"이라는 뜻입니다. 처럼 /bin/bash -c "$(curl -fsSL 주소)" 모양도 있습니다 — 로 스크립트 글 전체를 받아 bash -c 에 넘깁니다. 어느 모양이든 "받는다 → bash 가 실행한다"는 은 같습니다.
curl -fsSL https://example.com/install.sh | bash -s -- --version 1.2.0# 스크립트에 1.2.0 을 넘기기(예시 주소)/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"# Homebrew() 설치 — 같은 패턴의 다른 모양bash <(curl -fsSL https://sonub.com/install/hello.sh)# 받은 글을 파일처럼 bash 에 넘기기curl -fsSL https://sonub.com/install/hello.sh -o hello.sh && bash hello.sh# 저장해 두고, 읽은 뒤 실행하기는 와 언어마다 다르지만 모양은 하나입니다 — 관리자 · 할 일 · 이름. 할 일 이름도 비슷합니다. install· 는 설치, remove·uninstall·del 은 지우기, list· 는 목록, update·upgrade 는 새 판으로 바꾸기. 하나를 익히면 나머지는 낱말 몇 개만 바꾸면 됩니다.
sudo apk add figlet# (이 실습 )sudo apt install figlet# ·brew install figlet# ()pip install cowsay# — 안에서npm install ms# 프로젝트 — 에의 다른 도 와 같은 입니다. 실습 에서 gp 스킬을 에 설치하고(add), 전역 목록을 보고(list), 만 보고 다시 지워(remove) 보세요.
힌트 add 에서 쓴 -g(전역)와 -y(묻지 않기)는 list·remove 에서도 같은 뜻입니다. remove 는 지울 스킬 이름을 대상 자리에 받습니다.
npx skills add https://sonub.com -g -s gp -a claude-code -y
npx skills list -g
npx skills remove --help
npx skills remove gp -g -y
npx skills list -g
add · list · remove 는 모두 " 하위 명령 []" 모양입니다. -g 를 붙이면 셋 다 전역을 보고, -y 는 묻지 않습니다. remove 를 처음 써 봐도 --help 의 첫 줄(skills remove [skills...] [options])만 읽으면 gp 를 대상 자리에 두면 된다는 것을 압니다 — 외운 것이 아니라 패턴으로 쓴 것입니다.
답을 보기 전에 직접 풀어 보세요. 예제에서 사용하는 파일이 있는지 확인하고, 필요하면 연습용 파일을 먼저 만드세요. 내 컴퓨터에서 할 때도 실습용 폴더를 쓰세요.
Learn X in Y Minutes (, )를 참고해 재구성했습니다. 일부 은 개념 참고용이에요.
취소할 대기 예약을 선택하세요. 각 예약은 확인 후 취소됩니다.
내 :