[멋사 클라우드 5기] Day 33 & 34 - Linux (1)

2026. 3. 25. 09:05·Learning Log

Chapter 01. 리눅스 개요

리눅스란 무엇인가

리눅스(Linux)는 오픈소스 운영체제(Operating System)이다. 정확히 말하면, 리눅스는 커널(Kernel)의 이름이다. 커널이란 하드웨어와 소프트웨어 사이에서 중재자 역할을 하는 운영체제의 핵심 구성 요소이다. "리눅스"라고 부르는 것은 이 리눅스 커널 위에 다양한 시스템 유틸리티, 라이브러리, 셸(Shell), 패키지 매니저 등을 결합한 리눅스 배포판(Distribution)을 의미한다.

운영체제의 구조

┌─────────────────────────────────────┐
│          사용자 애플리케이션             │  ← 웹 브라우저, 에디터, Docker 등
├─────────────────────────────────────┤
│              셸 (Shell)              │  ← bash, zsh 등 명령어 해석기
├─────────────────────────────────────┤
│         시스템 유틸리티 / 라이브러리       │  ← GNU 도구들 (ls, cp, grep 등)
├─────────────────────────────────────┤
│         커널 (Kernel) — Linux        │  ← 프로세스, 메모리, 파일시스템, 네트워크 관리
├─────────────────────────────────────┤
│            하드웨어 (Hardware)        │  ← CPU, RAM, 디스크, NIC 등
└─────────────────────────────────────┘

하드웨어(Hardware)
CPU, 메모리(RAM), 디스크(SSD/HDD), 네트워크 인터페이스 카드(NIC) 등 물리적 장치이다. 운영체제 없이는 이 하드웨어를 직접 제어하기 어렵다.

커널(Kernel)
운영체제의 심장이다. 커널이 수행하는 핵심 기능은 다음과 같다:

  • 프로세스 관리: 어떤 프로그램이 CPU를 얼마나 사용할지 결정한다 (스케줄링)
  • 메모리 관리: 각 프로그램에 메모리를 할당하고, 부족하면 스왑(swap) 영역을 활용한다
  • 파일시스템 관리: 디스크에 데이터를 읽고 쓰는 방식을 제어한다
  • 디바이스 드라이버: 하드웨어 장치와 통신하기 위한 인터페이스를 제공한다
  • 네트워크 스택: TCP/IP 통신을 처리한다

시스템 유틸리티 / 라이브러리
커널 위에서 동작하는 기본 도구들이다. 파일을 복사하는 cp, 텍스트를 검색하는 grep, C 라이브러리인 glibc 등이 여기에 해당한다. 이 도구들의 상당수는 GNU 프로젝트에서 만들었기 때문에, 리눅스의 정식 명칭은 "GNU/Linux"이다.

셸(Shell)
사용자가 키보드로 입력한 명령어를 해석하여 커널에 전달하는 프로그램이다. 대표적으로 bash(Bourne Again Shell), zsh, sh 등이 있다. 셸은 단순한 명령어 해석기를 넘어서, 변수, 조건문, 반복문 등을 지원한다.

사용자 애플리케이션
최종 사용자가 직접 사용하는 프로그램이다. 웹 서버(Nginx, Apache), 컨테이너 런타임(Docker), 데이터베이스(MySQL, PostgreSQL) 등이 이 계층에서 동작한다.


왜 서버 환경에서 리눅스가 지배적인가

전 세계 서버의 약 96% 이상이 리눅스를 운영체제로 사용한다.

무료 & 오픈소스
라이선스 비용이 없다. 수천 대의 서버를 운영해도 OS 라이선스 비용은 0원이다.

안정성 & 보안
리눅스는 수십 년간 서버 환경에서 검증되었다. 커널과 주요 구성 요소들이 오픈소스이므로 전 세계 개발자들이 보안 취약점을 빠르게 발견하고 수정한다.

경량성
GUI 없이 CLI(Command Line Interface)만으로 운영할 수 있어 시스템 리소스를 효율적으로 사용한다. 이는 클라우드 환경에서 비용 절감과 직결된다.

자동화 친화적
모든 작업을 CLI와 스크립트로 수행할 수 있다. 이것이 DevOps의 핵심인 Infrastructure as Code(IaC), CI/CD 파이프라인, 설정 관리(Configuration Management)**를 가능하게 한다.


커널 (Kernel)

운영체제의 핵심이다. 하드웨어를 직접 제어하며, 애플리케이션이 하드웨어 리소스를 사용할 수 있도록 시스템 콜(System Call)이라는 인터페이스를 제공한다.

  • 시스템 콜(System Call)이란, 사용자 공간(User Space)의 프로그램이 커널 공간(Kernel Space)의 기능을 요청하는 메커니즘이다. 예를 들어 파일을 열 때(open()), 프로세스를 생성할 때(fork()), 네트워크 데이터를 보낼 때(send()) 모두 시스템 콜을 통해 커널에 요청한다.
┌──────────────────────────────┐
│       User Space (사용자 공간)  │  ← 애플리케이션, 셸, 유틸리티
│                              │
│    open(), read(), write()   │  ← 시스템 콜 호출
├──────────────────────────────┤
│      Kernel Space (커널 공간)  │  ← 프로세스 스케줄러, 메모리 관리자
│                              │     파일시스템 드라이버, 네트워크 스택
│      하드웨어 제어 코드           │
└──────────────────────────────┘

셸 (Shell)

사용자와 커널 사이의 인터페이스이다. 사용자가 명령어를 입력하면 셸이 이를 해석하여 커널에 전달한다.

주요 셸 종류:

셸 설명
sh (Bourne Shell) 가장 오래된 셸이다. POSIX 표준의 기반이다.
bash (Bourne Again Shell) sh의 개선판이다. 대부분의 리눅스 배포판에서 기본 셸로 사용된다.
zsh (Z Shell) bash의 기능을 확장한 셸이다. macOS의 기본 셸이다.
dash Debian 계열에서 /bin/sh로 사용하는 경량 셸이다. 스크립트 실행 속도가 빠르다.
fish 사용자 친화적인 셸이다. 자동완성 기능이 강력하다.

현재 사용 중인 셸 확인:

# 현재 셸 확인
echo $SHELL

# 사용 가능한 셸 목록 확인
cat /etc/shells

터미널 (Terminal)

터미널, 콘솔, 셸 — 이 세 가지 용어는 자주 혼용되지만 엄밀히 다르다:

  • 터미널(Terminal): 셸에 접근하기 위한 입출력 장치 또는 프로그램이다. 물리적 터미널에서 유래했으며, 현재는 소프트웨어 터미널 에뮬레이터(iTerm2, Windows Terminal, GNOME Terminal 등)를 의미한다.
  • 콘솔(Console): 시스템에 직접 연결된 물리적 터미널이다. 서버실에서 모니터와 키보드로 직접 접속하는 것이 콘솔 접속이다.
  • 셸(Shell): 터미널 안에서 실행되는 명령어 해석기 프로그램이다.

즉, 터미널은 창(window)이고, 셸은 그 창 안에서 동작하는 프로그램이다.

프롬프트 (Prompt) 읽는 법

터미널에 접속하면 다음과 같은 프롬프트가 표시된다:

username@hostname:~$
부분 의미
username 현재 로그인한 사용자 이름
@ 구분자
hostname 현재 시스템의 호스트 이름
: 구분자
~ 현재 위치한 디렉터리 (~는 홈)
$ 일반 사용자를 의미한다. #이면 root(관리자) 사용자이다.

명령어 기본 구조

command [options] [arguments]
  • command: 실행할 명령어 (예: ls, cd, grep)
  • options: 명령어의 동작을 변경하는 플래그 (예: l, -all, v)
  • arguments: 명령어가 처리할 대상 (예: 파일명, 디렉터리명)
# 예시
ls -la /var/log
#  │  │    └── argument (대상 디렉터리)
#  │  └── options (-l: 자세히, -a: 숨김파일 포함)
#  └── command (파일 목록 출력)

옵션의 두 가지 형태

# 짧은 옵션 (하이픈 하나 + 알파벳 한 글자)
ls -l
ls -a
ls -la        # 짧은 옵션은 합칠 수 있다

# 긴 옵션 (하이픈 두 개 + 단어)
ls --long
ls --all

도움말 확인하는 방법

# 1. --help 옵션 (간략한 도움말)
ls --help

# 2. man 명령어 (상세한 매뉴얼)
man ls
# q를 누르면 종료, /키워드로 검색, n으로 다음 검색 결과 이동

# 3. tldr (커뮤니티 기반 간결한 예시 — 별도 설치 필요)
tldr ls

# 4. type 명령어 (명령어의 종류 확인)
type ls      # ls is aliased to 'ls --color=auto'
type cd      # cd is a shell builtin
type grep    # grep is /usr/bin/grep

Chapter 02. 디렉터리 구조 & 탐색

리눅스 디렉터리 구조 개요

루트 디렉터리 (/)

리눅스의 모든 디렉터리는 루트 디렉터리(/) 에서 시작한다. Windows가 C:\, D:\ 등 드라이브 문자로 구분하는 것과 달리, 리눅스는 하나의 트리(tree) 구조로 모든 파일시스템을 통합한다. 외장 디스크를 연결하든, 네트워크 드라이브를 마운트하든, 모두 이 단일 트리 아래에 위치한다.

/                     ← 루트 디렉터리 (모든 것의 시작점)
├── bin/              ← 기본 명령어
├── boot/             ← 부팅에 필요한 파일
├── dev/              ← 디바이스 파일
├── etc/              ← 시스템 설정 파일
├── home/             ← 일반 사용자 홈 디렉터리
├── lib/              ← 공유 라이브러리
├── media/            ← 이동식 미디어 마운트 포인트
├── mnt/              ← 임시 마운트 포인트
├── opt/              ← 서드파티 소프트웨어
├── proc/             ← 프로세스 정보 (가상 파일시스템)
├── root/             ← root 사용자의 홈 디렉터리
├── run/              ← 런타임 데이터
├── sbin/             ← 시스템 관리 명령어
├── srv/              ← 서비스 데이터
├── sys/              ← 커널/하드웨어 정보 (가상 파일시스템)
├── tmp/              ← 임시 파일
├── usr/              ← 사용자 프로그램 및 데이터
└── var/              ← 가변 데이터 (로그, 캐시 등)

주요 디렉터리 상세 설명

/bin — 필수 사용자 명령어

모든 사용자가 사용할 수 있는 필수 명령어 바이너리(실행 파일)가 위치한다.

ls /bin/
# ls, cp, mv, rm, cat, echo, grep, mkdir, chmod, chown, ps, mount ...

참고: 최신 배포판(Ubuntu 20.04+, Fedora 등)에서는 /bin이 /usr/bin의 심볼릭 링크인 경우가 많다. 이를 UsrMerge라고 하며, /bin, /sbin, /lib을 각각 /usr/bin, /usr/sbin, /usr/lib으로 통합하는 추세이다.

/sbin — 시스템 관리 명령어

시스템 관리에 필요한 명령어가 위치한다. 주로 root 사용자가 사용하는 명령어들이다.

ls /sbin/
# fdisk, mkfs, iptables, reboot, shutdown, ifconfig, route ...

/bin과 /sbin의 차이는 대상 사용자이다. /bin은 모든 사용자용, /sbin은 관리자용이다.

/etc — 시스템 설정 파일

  • 시스템 전체에 적용되는 설정 파일(configuration files)이 위치한다.
# 주요 설정 파일들
/etc/hostname          # 시스템 호스트명
/etc/hosts             # 호스트명-IP 매핑 (로컬 DNS 역할)
/etc/resolv.conf       # DNS 서버 설정
/etc/fstab             # 파일시스템 마운트 정보 (부팅 시 자동 마운트)
/etc/passwd            # 사용자 계정 정보
/etc/shadow            # 사용자 비밀번호 (해시)
/etc/group             # 그룹 정보
/etc/sudoers           # sudo 권한 설정
/etc/ssh/sshd_config   # SSH 서버 설정
/etc/nginx/            # Nginx 웹 서버 설정 (설치 시)
/etc/systemd/          # systemd 서비스 설정
/etc/crontab           # 시스템 크론 작업
/etc/environment       # 시스템 전역 환경변수
/etc/apt/              # APT 패키지 매니저 설정 (Debian 계열)
/etc/yum.repos.d/      # YUM/DNF 저장소 설정 (Red Hat 계열)

서버 설정을 변경할 때는 거의 항상 /etc 아래의 파일을 편집하게 된다. 설정 파일을 수정하기 전에 반드시 백업하는 습관을 들여야 한다.

# 설정 파일 수정 전 백업
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)

/home — 일반 사용자 홈 디렉터리

각 일반 사용자의 개인 공간이다. 사용자 devops가 있다면 /home/devops가 해당 사용자의 홈 디렉터리이다.

/home/
├── devops/           # devops 사용자의 홈
│   ├── .bashrc       # bash 셸 설정 (숨김 파일)
│   ├── .ssh/         # SSH 키 저장소
│   ├── .profile      # 로그인 시 실행되는 스크립트
│   └── projects/     # 사용자가 만든 디렉터리
└── deploy/           # deploy 사용자의 홈

숨김 파일: 리눅스에서 파일명이 .(점)으로 시작하면 숨김 파일이다. ls로는 보이지 않고, ls -a를 사용해야 보인다. 사용자 설정 파일들은 대부분 숨김 파일이다.

~ (틸드): 현재 사용자의 홈 디렉터리를 나타내는 축약어이다.

# 다음 두 명령어는 동일하다 (현재 사용자가 devops인 경우)
cd /home/devops
cd ~

# 다른 사용자의 홈 디렉터리
cd ~deploy    # /home/deploy로 이동

/var — 가변 데이터

시스템이 운영되면서 크기가 변하는(variable) 데이터가 저장된다. 로그, 캐시, 메일, 스풀 등이 여기에 위치한다.

/var/
├── log/              # 시스템 및 애플리케이션 로그 ★★★
│   ├── syslog        # 시스템 로그 (Debian 계열)
│   ├── messages      # 시스템 로그 (Red Hat 계열)
│   ├── auth.log      # 인증 로그 (로그인, sudo 등)
│   ├── kern.log      # 커널 로그
│   ├── nginx/        # Nginx 로그
│   └── journal/      # systemd 저널 로그
├── cache/            # 애플리케이션 캐시
│   └── apt/          # APT 패키지 캐시
├── lib/              # 가변 상태 데이터
│   ├── docker/       # Docker 데이터 (이미지, 컨테이너, 볼륨)
│   └── mysql/        # MySQL 데이터
├── tmp/              # 재부팅 시에도 유지되는 임시 파일
├── spool/            # 처리 대기 중인 데이터 (메일, 프린트)
└── run/              # 실행 중인 프로세스의 런타임 데이터

/var/log는 트러블슈팅의 시작점이다. 문제가 발생하면 가장 먼저 확인하는 곳이다. /var가 위치한 파티션이 꽉 차면 시스템 전체에 문제가 생길 수 있으므로, 디스크 용량 모니터링에서 /var는 특별히 주의해야 한다.

/proc — 프로세스 정보 (가상 파일시스템)

/proc는 실제 디스크에 존재하는 디렉터리가 아니다. 커널이 메모리 상에서 동적으로 생성하는 가상 파일시스템이다. 현재 실행 중인 프로세스 정보와 시스템 상태를 파일 형태로 제공한다.

/proc/
├── 1/                # PID 1 (init/systemd) 프로세스 정보
│   ├── cmdline       # 프로세스 실행 명령어
│   ├── status        # 프로세스 상태 (메모리 사용량 등)
│   ├── fd/           # 열린 파일 디스크립터 목록
│   └── environ       # 프로세스 환경변수
├── cpuinfo           # CPU 정보
├── meminfo           # 메모리 정보
├── diskstats         # 디스크 I/O 통계
├── net/              # 네트워크 관련 정보
│   ├── tcp           # TCP 연결 정보
│   └── dev           # 네트워크 인터페이스 통계
├── loadavg           # 시스템 부하 평균
├── uptime            # 시스템 가동 시간
└── version           # 커널 버전 정보
# 활용 예시
cat /proc/cpuinfo       # CPU 정보 확인
cat /proc/meminfo       # 메모리 상세 정보
cat /proc/loadavg       # 시스템 부하 (load average)
cat /proc/version       # 커널 버전
cat /proc/1/cmdline     # PID 1 프로세스의 실행 명령어
ls -la /proc/self/fd    # 현재 프로세스의 열린 파일 목록

왜 중요한가: 모니터링 도구(Prometheus node_exporter, Datadog agent 등)가 시스템 메트릭을 수집할 때 바로 이 /proc 파일시스템에서 데이터를 읽는다. top, htop, free 같은 명령어도 내부적으로 /proc를 읽어서 정보를 표시한다.

/sys — 커널/하드웨어 정보 (가상 파일시스템)

/proc와 유사한 가상 파일시스템이지만, /sys는 커널 오브젝트와 하드웨어 장치에 대한 정보를 체계적으로 제공한다. /proc가 프로세스 중심이라면, /sys는 하드웨어/디바이스 중심이다.

# 네트워크 인터페이스 정보
ls /sys/class/net/
# eth0  lo

# 블록 디바이스(디스크) 정보
ls /sys/block/
# sda  nvme0n1

/dev — 디바이스 파일

하드웨어 장치를 파일로 표현한 것이다.

/dev/
├── sda               # 첫 번째 SCSI/SATA 디스크
├── sda1              # 첫 번째 디스크의 첫 번째 파티션
├── nvme0n1           # 첫 번째 NVMe SSD
├── nvme0n1p1         # NVMe SSD의 첫 번째 파티션
├── tty0              # 가상 콘솔
├── null              # 블랙홀 — 쓴 데이터는 사라진다
├── zero              # 무한히 0(null byte)을 출력한다
├── random            # 랜덤 데이터를 생성한다
└── urandom           # 비차단 랜덤 데이터 생성

특수 장치 파일의 활용:

# 출력을 버리고 싶을 때
command > /dev/null 2>&1

# 파일을 0으로 채워서 보안 삭제
dd if=/dev/zero of=file_to_wipe bs=1M count=100

# 랜덤 비밀번호 생성
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32

/tmp — 임시 파일

임시 파일을 저장하는 디렉터리이다. 재부팅하면 삭제될 수 있다 (배포판에 따라 다름).
모든 사용자가 읽고 쓸 수 있다.

# 임시 파일 생성
mktemp    # /tmp/tmp.XXXXXXXXXX 형식의 고유한 파일 생성

보안 주의: /tmp는 모든 사용자가 접근 가능하므로, 민감한 데이터를 저장하면 안 된다. Sticky Bit가 설정되어 있어서 다른 사용자의 파일은 삭제할 수 없지만, 읽기는 가능할 수 있다.

/usr — 사용자 프로그램 및 데이터

"Unix System Resources"의 약자이다 (User가 아니다). 시스템에 설치된 프로그램, 라이브러리, 문서 등이 위치한다.

/usr/
├── bin/              # 사용자 명령어 (대부분의 명령어가 여기에)
├── sbin/             # 시스템 관리 명령어
├── lib/              # 라이브러리
├── local/            # 로컬에서 직접 컴파일하여 설치한 소프트웨어
│   ├── bin/
│   ├── lib/
│   └── etc/
├── share/            # 아키텍처 독립적 데이터 (매뉴얼, 문서 등)
│   └── man/          # man 페이지
└── include/          # C/C++ 헤더 파일

경로 (Path)

절대 경로 (Absolute Path)

루트 디렉터리(/)부터 시작하는 전체 경로이다. 어디서든 동일한 위치를 가리킨다.

/home/devops/projects/myapp/config.yaml
/var/log/nginx/access.log
/etc/ssh/sshd_config

상대 경로 (Relative Path)

현재 위치(CWD, Current Working Directory)를 기준으로 하는 경로이다. /로 시작하지 않는다.

# 현재 /home/devops에 있다고 가정
cd projects/myapp      # /home/devops/projects/myapp로 이동
cat config.yaml        # /home/devops/projects/myapp/config.yaml

# 현재 위치에 따라 가리키는 곳이 달라진다

특수 경로 표기

표기 의미 예시
. 현재 디렉터리 ./script.sh (현재 디렉터리의 스크립트 실행)
.. 상위(부모) 디렉터리 cd .. (한 단계 위로 이동)
~ 현재 사용자의 홈 디렉터리 cd ~ → /home/username
~user 특정 사용자의 홈 디렉터리 cd ~deploy → /home/deploy
- 이전 디렉터리 cd - (직전에 있던 디렉터리로 이동)

디렉터리 탐색 명령어

pwd — 현재 위치 확인

Print Working Directory의 약자이다. 현재 작업 중인 디렉터리의 절대 경로를 출력한다.

$ pwd
/home/devops/projects

# 심볼릭 링크를 따르지 않고 실제 물리 경로를 표시
$ pwd -P
/data/projects    # 실제 경로 (심볼릭 링크가 아닌)

팁: 셸 스크립트에서 현재 스크립트의 위치를 기준으로 작업할 때 자주 사용한다.

# 스크립트 파일이 위치한 디렉터리로 이동
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"

cd — 디렉터리 이동

Change Directory의 약자이다. 디렉터리를 이동하는 가장 기본적인 명령어이다.

# 기본 사용법
cd /var/log              # 절대 경로로 이동
cd nginx                 # 상대 경로로 이동 (현재 위치 기준)
cd ..                    # 상위 디렉터리로 이동
cd ../..                 # 두 단계 상위로 이동
cd ~                     # 홈 디렉터리로 이동
cd                       # 인자 없이 — 홈 디렉터리로 이동 (cd ~와 동일)
cd -                     # 이전 디렉터리로 이동 (토글)

ls — 디렉터리 내용 나열

List의 약자이다. 디렉터리의 내용물(파일, 하위 디렉터리)을 나열한다. 가장 자주 사용하는 명령어 중 하나이다.

ls                       # 현재 디렉터리의 내용
ls /var/log              # 특정 디렉터리의 내용
ls file.txt              # 특정 파일 정보
ls *.log                 # 와일드카드 — .log로 끝나는 파일만

주요 옵션

ls -l                    # 긴 형식 (자세한 정보)
ls -a                    # 숨김 파일(.으로 시작) 포함
ls -la                   # -l과 -a 조합 (가장 많이 사용하는 조합)
ls -lh                   # 파일 크기를 사람이 읽기 쉬운 형태로 (K, M, G)

ls -l 출력 상세 해석

$ ls -la /var/log/
total 12345
drwxrwxr-x  12 root   syslog  4096 Mar 23 10:30 .
drwxr-xr-x  14 root   root    4096 Jan 15 08:00 ..
-rw-r-----   1 syslog adm    98234 Mar 23 10:30 syslog
-rw-r-----   1 syslog adm   234567 Mar 22 23:59 syslog.1
drwxr-xr-x   2 root   root    4096 Mar 20 00:00 nginx
lrwxrwxrwx   1 root   root      39 Jan 15 08:00 mail.log -> /var/log/mail/current

각 필드의 의미를 분해하면:

-rw-r-----   1   syslog   adm   98234   Mar 23 10:30   syslog
│├─┤├─┤├─┤   │     │       │      │         │             │
│ │  │  │    │     │       │      │         │             └─ 파일명
│ │  │  │    │     │       │      │         └─ 최종 수정 시간
│ │  │  │    │     │       │      └─ 파일 크기 (byte)
│ │  │  │    │     │       └─ 소유 그룹
│ │  │  │    │     └─ 소유자
│ │  │  │    └─ 하드 링크 수
│ │  │  └─ 기타(other) 사용자 권한 (---)
│ │  └─ 그룹(group) 권한 (r--)
│ └─ 소유자(owner) 권한 (rw-)
└─ 파일 타입

파일 타입 문자:

문자 의미
- 일반 파일
d 디렉터리
l 심볼릭 링크
c 문자 디바이스 (터미널 등)
b 블록 디바이스 (디스크 등)
s 소켓
p Named pipe (FIFO)

tree — 트리 구조로 표시

디렉터리 구조를 시각적인 트리 형태로 보여준다. 기본 설치가 아닌 경우가 많으므로 설치가 필요할 수 있다.

# 설치 (없는 경우)
sudo apt install tree       # Debian/Ubuntu

# 기본 사용법
tree                        # 현재 디렉터리의 트리 구조
tree /etc/nginx             # 특정 디렉터리의 트리 구조
tree -L 2                   # 깊이 2단계까지만 표시 ★
tree -d                     # 디렉터리만 표시
tree -a                     # 숨김 파일 포함
tree -h                     # 파일 크기 표시 (사람이 읽기 쉬운 형태)
tree -P "*.conf"            # 특정 패턴 파일만 표시
tree -I "node_modules|.git" # 특정 디렉터리 제외
tree --dirsfirst            # 디렉터리를 먼저 표시

find — 파일/디렉터리 검색

파일시스템에서 파일이나 디렉터리를 다양한 조건으로 검색하는 강력한 명령어이다.

find [검색 시작 경로] [검색 조건] [동작]

이름으로 검색

# 파일명으로 검색 (대소문자 구분)
find /etc -name "nginx.conf"

# 파일명으로 검색 (대소문자 무시)
find /etc -iname "*.CONF"

# 와일드카드 사용
find /var/log -name "*.log"
find / -name "docker-compose*.yml"

타입으로 검색

# 파일만 검색
find /home -type f -name "*.sh"

# 디렉터리만 검색
find /var -type d -name "log"

# 심볼릭 링크만 검색
find /etc -type l

크기로 검색

# 100MB 이상인 파일 검색
find / -type f -size +100M

# 1KB 미만인 파일 검색
find /tmp -type f -size -1k

# 정확히 0byte (빈 파일)
find /var/log -type f -empty

# 빈 디렉터리
find /home -type d -empty

시간으로 검색

# 최근 7일 이내에 수정된 파일
find /var/log -type f -mtime -7

# 30일 이상 된(수정되지 않은) 파일
find /tmp -type f -mtime +30

# 최근 60분 이내에 수정된 파일
find /var/log -type f -mmin -60

# 최근 1일 이내에 접근된 파일
find /home -type f -atime -1

시간 옵션:

옵션 의미 단위
-mtime 내용이 수정(modify)된 시간 일(day)
-atime 접근(access)된 시간 일(day)
-ctime 메타데이터가 변경(change)된 시간 일(day)
-mmin 내용이 수정된 시간 분(minute)
-amin 접근된 시간 분(minute)
-cmin 메타데이터가 변경된 시간 분(minute)

권한/소유자로 검색

# 권한이 777인 파일 (보안 위험 — 누구나 읽기/쓰기/실행 가능)
find / -type f -perm 777

# 소유자가 없는 파일 (사용자가 삭제된 경우)
find / -type f -nouser

# 특정 사용자 소유 파일
find /home -type f -user devops

# 특정 그룹 소유 파일
find /var -type f -group www-data

검색 결과에 동작 수행 (exec)

find의 가장 강력한 기능은 검색 결과에 대해 명령어를 실행할 수 있다는 것이다.

# 검색된 파일의 상세 정보 출력
find /var/log -name "*.log" -exec ls -lh {} \;

# 30일 이상 된 로그 파일 삭제
find /var/log -name "*.log" -mtime +30 -exec rm -f {} \;

# 검색된 파일의 권한을 644로 변경
find /var/www -type f -exec chmod 644 {} \;

# 검색된 디렉터리의 권한을 755로 변경
find /var/www -type d -exec chmod 755 {} \;
  • exec 문법 설명:
  • {} : 검색된 각 파일/디렉터리의 경로가 들어가는 자리이다
  • \; : exec 명령어의 끝을 표시한다 (세미콜론을 이스케이프)
  • + : \; 대신 사용하면 검색 결과를 한 번에 전달하여 성능이 향상된다
# \; → 파일마다 명령어를 한 번씩 실행 (느림)
find /var/log -name "*.log" -exec ls -l {} \;

# + → 파일을 모아서 명령어를 한 번에 실행 (빠름)
find /var/log -name "*.log" -exec ls -l {} +

조건 조합

# AND (기본 동작 — 조건을 나열하면 AND)
find /var/log -name "*.log" -size +10M

# OR (-o 옵션)
find /etc -name "*.conf" -o -name "*.cfg"

# NOT (! 또는 -not)
find /home -type f ! -name "*.tmp"

# 복합 조건: /var/log에서 7일 이상 되고 100MB 이상인 .log 파일
find /var/log -type f -name "*.log" -mtime +7 -size +100M

실무 활용 시나리오

# 1. 디스크 정리 — 큰 파일 찾기
find / -type f -size +500M 2>/dev/null | head -20

# 2. 보안 점검 — 권한이 너무 열려있는 파일 찾기
find / -type f -perm -o+w 2>/dev/null

# 3. 최근 변경된 설정 파일 확인 (트러블슈팅)
find /etc -type f -mmin -30

# 4. 특정 확장자 파일 일괄 삭제
find /tmp -type f -name "*.tmp" -mtime +7 -delete

# 5. SUID 비트 설정된 파일 찾기 (보안 감사)
find / -type f -perm -4000 2>/dev/null

which, whereis, type — 명령어 위치 찾기

# which: 실행 파일의 경로 (PATH에서 검색)
$ which python3
/usr/bin/python3

$ which nginx
/usr/sbin/nginx

# whereis: 바이너리, 소스, man 페이지 위치
$ whereis nginx
nginx: /usr/sbin/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz

# type: 명령어의 종류 (alias, builtin, file 등)
$ type cd
cd is a shell builtin

$ type ls
ls is aliased to 'ls --color=auto'

$ type python3
python3 is /usr/bin/python3

which와 type의 차이:

  • which는 PATH 환경변수에서 실행 파일의 경로만 찾는다
  • type은 셸 빌트인(built-in) 명령어, 앨리어스(alias), 함수까지 구분하여 알려준다

파일시스템과 마운트 개념

파일시스템 (Filesystem)이란

파일시스템은 디스크에 데이터를 저장하고 조직하는 방식이다.
도서관에서 책을 분류하고 찾는 시스템에 비유할 수 있다.

마운트 (Mount)란

마운트는 파일시스템을 디렉터리 트리의 특정 위치에 연결하는 것이다. 리눅스에서는 디스크를 연결하면 자동으로 접근할 수 있는 것이 아니라, 반드시 특정 디렉터리에 마운트해야 한다.

물리 디스크 /dev/sdb1  ──mount──→  /data  (디렉터리 트리에 연결)

마운트 이후에는 /data 경로를 통해 해당 디스크에 접근할 수 있다.

# 현재 마운트된 파일시스템 확인
mount | column -t
df -hT

# 수동 마운트
sudo mount /dev/sdb1 /mnt/data

# 언마운트
sudo umount /mnt/data

inode와 파일시스템 내부 구조

inode란

inode(Index Node)는 파일시스템에서 파일의 메타데이터(metadata)를 저장하는 데이터 구조이다. 모든 파일과 디렉터리는 하나의 inode를 가진다.

inode에 저장되는 정보:

  • 파일 타입 (일반 파일, 디렉터리, 심볼릭 링크 등)
  • 권한 (permissions)
  • 소유자 (UID)와 그룹 (GID)
  • 파일 크기
  • 타임스탬프 (생성, 수정, 접근 시간)
  • 하드 링크 수
  • 데이터 블록의 위치 (포인터)

중요: inode에는 파일 이름이 저장되지 않는다. 파일 이름은 디렉터리 엔트리에 저장된다. 디렉터리란 본질적으로 "파일명 ↔ inode 번호"의 매핑 테이블이다.

# 파일의 inode 번호 확인
ls -i /etc/hostname
# 131074 /etc/hostname

# 상세 inode 정보 확인
stat /etc/hostname
#   File: /etc/hostname
#   Size: 12          Blocks: 8          IO Block: 4096   regular file
# Device: 801h/2049d  Inode: 131074      Links: 1
# Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
# Access: 2025-03-23 10:00:00.000000000 +0900
# Modify: 2025-01-15 08:00:00.000000000 +0900
# Change: 2025-01-15 08:00:00.000000000 +0900

Chapter 03. 파일 & 디렉터리 관리

파일과 디렉터리의 기본 개념

리눅스에서 파일은 바이트(byte)의 연속된 스트림이다. Windows와 달리 리눅스는 파일 확장자에 의존하지 않는다. .txt, .log, .conf 같은 확장자는 사람이 파일의 용도를 구분하기 위한 관례(convention)일 뿐이며, 시스템이 파일의 종류를 결정하는 기준은 아니다.

파일명 규칙

리눅스 파일명은 Windows보다 자유도가 높지만, 알아두어야 할 규칙이 있다:

  • 대소문자를 구분한다: File.txt와 file.txt는 다른 파일이다
  • 최대 255자까지 가능하다 (ext4 기준)
  • 거의 모든 문자를 사용할 수 있다: 사용할 수 없는 문자는 /(경로 구분자)와 NULL(문자열 종결자)뿐이다
  • .으로 시작하면 숨김 파일이다: .bashrc, .ssh/, .gitignore 등
  • 공백과 특수문자는 피하는 것이 좋다: 셸 스크립트에서 문제를 일으킬 수 있다
# 공백이 포함된 파일명 다루기 (반드시 따옴표 사용)
ls "my file.txt"
rm "my file.txt"

# 하이픈(-)으로 시작하는 파일명 다루기 (옵션으로 인식되는 문제)
rm -- -filename       # -- 이후는 옵션이 아님을 표시
rm ./-filename        # 상대 경로로 지정

타임스탬프 (Timestamps)

리눅스의 모든 파일은 세 가지 타임스탬프를 가진다:

타임스탬프 약자 설명 변경되는 시점
Modify time (mtime) m 파일 내용이 마지막으로 변경된 시간 파일에 데이터를 쓸 때
Access time (atime) a 파일이 마지막으로 읽힌 시간 파일을 읽을 때 (cat, less 등)
Change time (ctime) c 파일의 메타데이터가 마지막으로 변경된 시간 권한, 소유자, 이름 변경 시
# stat 명령어로 세 가지 타임스탬프 확인
$ stat config.yaml
  File: config.yaml
  Size: 1234        Blocks: 8          IO Block: 4096   regular file
Access: 2025-03-23 14:30:00.000000000 +0900
Modify: 2025-03-20 09:15:00.000000000 +0900
Change: 2025-03-20 09:15:00.000000000 +0900
 Birth: 2025-03-01 10:00:00.000000000 +0900

참고: 생성 시간(Birth/Creation time)은 전통적인 UNIX에는 없었으나, ext4와 최신 커널에서는 지원한다. stat 명령어의 Birth 필드에서 확인할 수 있다.

noatime 마운트 옵션: 서버 환경에서는 /etc/fstab에 noatime 옵션을 설정하여 atime 업데이트를 비활성화하는 경우가 많다. 파일을 읽을 때마다 디스크에 쓰기(atime 업데이트)가 발생하면 성능 저하의 원인이 되기 때문이다.


디렉터리 생성 — mkdir

기본 사용법

Make Directory의 약자이다. 새 디렉터리를 생성한다.

# 단일 디렉터리 생성
mkdir projects

# 여러 디렉터리 한 번에 생성
mkdir dir1 dir2 dir3

# 중첩 디렉터리 한 번에 생성 (-p 옵션) ★★★
mkdir -p projects/backend/src/main
# -p 없이 하면 상위 디렉터리가 없으면 에러 발생
# mkdir: cannot create directory 'projects/backend/src/main': No such file or directory

Brace Expansion을 활용한 구조 생성

셸의 Brace Expansion({}) 기능을 활용하면 복잡한 디렉터리 구조를 한 줄로 생성할 수 있다.

# 프로젝트 기본 구조 한 번에 생성
mkdir -p myapp/{src,test,docs,config,scripts}

# 더 복잡한 구조
mkdir -p myapp/{src/{main,lib},test/{unit,integration},deploy/{dev,staging,prod}}

# 결과 확인
$ tree myapp/
myapp/
├── deploy
│   ├── dev
│   ├── prod
│   └── staging
├── src
│   ├── lib
│   └── main
└── test
    ├── integration
    └── unit

파일 생성

touch — 빈 파일 생성 / 타임스탬프 변경

touch의 원래 목적은 파일의 타임스탬프를 변경하는 것이다. 하지만 대상 파일이 존재하지 않으면 빈 파일을 생성하기 때문에, 빈 파일 생성 용도로도 자주 사용한다.

# 빈 파일 생성
touch newfile.txt

# 여러 파일 한 번에 생성
touch file1.txt file2.txt file3.txt

# Brace Expansion 활용
touch log-{01..12}.txt
# log-01.txt log-02.txt ... log-12.txt 생성

리다이렉션으로 파일 생성

# 빈 파일 생성 (touch과 동일한 효과)
> newfile.txt

# 내용이 있는 파일 생성
echo "Hello, World!" > hello.txt

# 여러 줄 파일 생성 (Here Document)
cat << EOF > config.yaml
server:
  host: 0.0.0.0
  port: 8080
database:
  host: localhost
  port: 5432
EOF

Here Document (<< EOF): EOF(End Of File)는 구분자이며, 임의의 문자열을 사용할 수 있다. 여기서부터 같은 구분자가 나올 때까지의 내용이 입력으로 전달된다. 설정 파일을 스크립트로 생성할 때 매우 유용하다.


복사 — cp

Copy의 약자이다. 파일이나 디렉터리를 복사한다.

# 파일 복사
cp source.txt destination.txt

# 파일을 다른 디렉터리로 복사
cp config.yaml /tmp/

# 파일을 다른 디렉터리로 복사하면서 이름 변경
cp config.yaml /tmp/config.yaml.bak

활용 패턴

# 1. 설정 파일 백업 (날짜 포함) ★★★
cp -p /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d_%H%M%S)

# 2. 디렉터리 전체 백업 (메타데이터 보존)
cp -a /var/www/html/ /backup/www-$(date +%Y%m%d)/

# 3. 여러 파일을 디렉터리로 복사
cp file1.txt file2.txt file3.txt /destination/

# 4. 와일드카드로 특정 파일만 복사
cp /var/log/*.log /backup/logs/

# 5. 빈 디렉터리 구조만 복사 (find + mkdir 조합)
cd /source && find . -type d -exec mkdir -p /dest/{} \;

cp의 동작 원리

cp는 원본 파일의 데이터를 읽어서 새로운 inode를 가진 새 파일을 생성한다. 즉, 원본과 복사본은 완전히 독립적인 파일이다. 한쪽을 수정해도 다른 쪽에 영향이 없다.


이동 / 이름 변경 — mv

Move의 약자이다. 파일이나 디렉터리를 이동하거나 이름을 변경한다. 리눅스에는 별도의 "rename" 명령어가 기본 제공되지 않으며, mv가 이름 변경 기능을 겸한다.

# 파일 이름 변경
mv old_name.txt new_name.txt

# 파일을 다른 디렉터리로 이동
mv report.pdf /home/devops/documents/

# 이동하면서 이름 변경
mv config.yaml /etc/myapp/application.yaml

# 디렉터리 이름 변경 (디렉터리도 동일하게 동작)
mv old_dir/ new_dir/

# 디렉터리를 다른 위치로 이동
mv projects/ /opt/

삭제 — rm, rmdir

rm — 파일/디렉터리 삭제

Remove의 약자이다. 파일이나 디렉터리를 삭제한다.

⚠️ 경고: 리눅스에는 휴지통(Recycle Bin)이 없다. rm으로 삭제한 파일은 복구가 매우 어렵다. 특히 rm -rf는 확인 없이 재귀적으로 모든 것을 삭제하므로 극도로 주의해야 한다.

# 파일 삭제
rm file.txt

# 여러 파일 삭제
rm file1.txt file2.txt file3.txt

# 와일드카드로 삭제
rm *.tmp
rm *.log

rmdir — 빈 디렉터리만 삭제

rmdir은 비어있는 디렉터리만 삭제할 수 있다. 내용물이 있으면 에러가 발생한다.

# 빈 디렉터리 삭제
rmdir empty_dir/

# 에러 발생 — 디렉터리가 비어있지 않음
rmdir non_empty_dir/
# rmdir: failed to remove 'non_empty_dir/': Directory not empty

# -p : 빈 상위 디렉터리까지 함께 삭제
rmdir -p a/b/c/     # c, b, a 순서로 삭제 (모두 비어있어야 함)

안전한 삭제 습관

# 1. 삭제 전에 항상 먼저 ls로 확인
ls /var/log/*.log.1          # 삭제 대상 확인
rm /var/log/*.log.1          # 확인 후 삭제

# 2. rm -rf를 사용할 때는 경로를 절대 변수에 넣지 말 것
# 위험한 패턴 — 변수가 비어있으면 / 를 삭제하게 된다
rm -rf ${DIR}/               # DIR이 빈 문자열이면 rm -rf / 실행 ☠️

# 안전한 패턴
rm -rf "${DIR:?Variable is not set}/"   # 변수가 비어있으면 에러 발생

# 3. 삭제 대신 이동으로 대체 (안전한 삭제 패턴)
mv old_files/ /tmp/trash/    # 나중에 확인 후 /tmp는 재부팅 시 자동 삭제

# 4. interactive 옵션 활용
alias rm='rm -i'             # 별칭 설정 (모든 rm에 확인 절차 추가)

# 5. 중요한 작업 전에 pwd 확인
pwd                          # 현재 위치가 맞는지 확인
rm -rf build/                # 그 후에 삭제

wc — 파일 통계

Word Count의 약자이다. 파일의 줄 수, 단어 수, 바이트 수를 출력한다.

$ wc /etc/passwd
  42   68  2156  /etc/passwd
#  │    │    │
#  │    │    └─ 바이트 수
#  │    └─ 단어 수
#  └─ 줄 수

# 줄 수만 출력 (-l: lines) ★ 가장 자주 사용
wc -l /var/log/syslog
# 15234 /var/log/syslog

# 단어 수만 출력 (-w: words)
wc -w document.txt

# 바이트 수만 출력 (-c: bytes)
wc -c data.bin

# 문자 수만 출력 (-m: characters, 멀티바이트 문자 지원)
wc -m korean_text.txt

# 여러 파일의 줄 수 확인
wc -l /var/log/*.log
#   1234 /var/log/auth.log
#   5678 /var/log/syslog
#    234 /var/log/kern.log
#   7146 total

# 파이프와 조합 — 프로세스 수 세기
ps aux | wc -l

와일드카드 (Globbing)

셸에서 파일명 패턴을 매칭하는 특수 문자를 와일드카드(wildcard) 또는 글로빙(globbing)이라고 한다. find의 정규표현식과는 다른 개념이다. 와일드카드는 셸이 명령어를 실행하기 전에 파일명으로 확장(expand)한다.

기본 와일드카드

패턴 의미 예시
* 0개 이상의 임의의 문자 *.log → error.log, access.log
? 정확히 1개의 임의의 문자 file?.txt → file1.txt, fileA.txt
[abc] 괄호 안의 문자 중 하나 file[123].txt → file1.txt, file2.txt
[a-z] 범위 내의 문자 중 하나 file[a-c].txt → filea.txt, fileb.txt
[!abc] 또는 [^abc] 괄호 안의 문자가 아닌 것 file[!0-9].txt → filea.txt

확장 글로빙 (bash)

bash에서는 extglob 옵션으로 더 강력한 패턴 매칭을 사용할 수 있다.

# extglob 활성화 (보통 기본 활성화)
shopt -s extglob

# ?(pattern)  : 패턴이 0번 또는 1번
# *(pattern)  : 패턴이 0번 이상
# +(pattern)  : 패턴이 1번 이상
# @(pattern)  : 패턴이 정확히 1번
# !(pattern)  : 패턴에 매치되지 않는 것

# .log와 .tmp를 제외한 모든 파일
ls !(*.log|*.tmp)

# .conf 또는 .yaml 파일만
ls *.@(conf|yaml)

Brace Expansion ({})

와일드카드와는 다른 메커니즘이지만, 파일 관리에서 매우 유용하다. 글로빙은 존재하는 파일을 매칭하지만, Brace Expansion은 문자열을 생성한다.

# 문자열 목록 생성
echo {apple,banana,cherry}
# apple banana cherry

# 범위 생성
echo {1..10}
# 1 2 3 4 5 6 7 8 9 10

echo {a..z}
# a b c d e f g h i j k l m n o p q r s t u v w x y z

echo {01..12}
# 01 02 03 04 05 06 07 08 09 10 11 12

# 증가값 지정
echo {0..100..10}
# 0 10 20 30 40 50 60 70 80 90 100

# 실무 활용
# 1. 파일 백업
cp config.yaml{,.bak}           # config.yaml → config.yaml.bak으로 복사
# 확장: cp config.yaml config.yaml.bak

# 2. 여러 디렉터리 생성
mkdir -p project/{src,test,docs,build}

# 3. 확장자 변경 (rename 효과)
mv report.{txt,md}              # report.txt → report.md
# 확장: mv report.txt report.md

복수 파일/디렉터리 일괄 처리

xargs — 표준 입력을 명령어 인자로 변환

xargs는 파이프를 통해 전달된 표준 입력(stdin)을 명령어의 인자(argument)로 변환한다. find와 함께 사용하면 매우 강력하다.

# find 결과를 xargs로 전달
find /tmp -name "*.tmp" -mtime +7 | xargs rm -f

# 파일명에 공백이 있을 때 안전하게 처리 ★★★
find /tmp -name "*.tmp" -print0 | xargs -0 rm -f
# -print0: null 문자로 구분
# -0: null 문자를 구분자로 인식

# 한 번에 처리할 인자 수 제한
find . -name "*.log" | xargs -n 5 ls -l
# 5개씩 묶어서 ls -l 실행

# 자리 표시자(placeholder) 사용 (-I)
find . -name "*.conf" | xargs -I {} cp {} /backup/{}.bak

# 병렬 처리 (-P: 동시 실행할 프로세스 수)
find . -name "*.png" | xargs -P 4 -I {} convert {} -resize 50% resized_{}

find + exec vs xargs 비교

# find -exec: 파일 하나씩 명령어 실행
find . -name "*.log" -exec gzip {} \;

# find -exec +: 가능한 많은 파일을 한 번에 전달
find . -name "*.log" -exec gzip {} +

# xargs: find의 출력을 파이프로 받아서 전달
find . -name "*.log" | xargs gzip

일반적으로 xargs가 -exec \;보다 빠르다. -exec +와 xargs는 성능이 비슷하다. 파일명에 특수문자(공백, 개행)가 있을 수 있다면 find -print0 | xargs -0 조합을 사용하는 것이 가장 안전하다.

핵심 원칙 정리

  1. 삭제 전에 반드시 ls로 확인한다
  2. 설정 파일 수정 전에 반드시 백업한다 (cp -p file file.bak.$(date +%Y%m%d))
  3. rm -rf에 변수를 사용할 때는 변수가 비어있지 않은지 검증한다
  4. 파일명에 공백이 있을 수 있으면 find -print0 | xargs -0 조합을 사용한다
  5. 같은 파티션의 mv는 즉시, 다른 파티션의 mv는 시간이 걸린다는 점을 기억한다
  6. rm은 unlink이다 — 프로세스가 파일을 잡고 있으면 공간이 해제되지 않는다

Chapter 04. 파일 내용 확인 & 검색

파일 내용을 확인하는 방법

리눅스에서 파일 내용을 확인하는 명령어는 여러 가지가 있다.

상황 적합한 명령어
짧은 파일 전체 보기 cat
긴 파일을 페이지 단위로 읽기 less
파일의 앞/뒤 일부만 보기 head, tail
실시간 로그 모니터링 tail -f
파일 간 차이 빠르게 비교 diff

cat — 파일 전체 출력

Concatenate의 약자이다. 원래 목적은 여러 파일을 연결(concatenate)하여 출력하는 것이지만, 단일 파일의 내용을 확인하는 용도로 가장 흔히 사용한다.

# 파일 내용 출력
cat /etc/hostname

# 줄 번호와 함께 출력
cat -n /etc/passwd

# 빈 줄을 제외하고 줄 번호 표시
cat -b /etc/ssh/sshd_config

# 여러 파일 연결하여 출력
cat header.txt body.txt footer.txt

# 여러 파일을 하나로 합치기
cat part1.log part2.log part3.log > combined.log

언제 쓰고, 언제 쓰지 말아야 하는가:

  • 수십 줄 이하의 짧은 파일 → cat 적합
  • 수백~수천 줄 이상의 파일 → cat은 부적합 (터미널이 스크롤로 넘쳐버린다). less를 사용한다.

tac — 역순 출력

cat의 철자를 뒤집은 이름 그대로, 파일의 마지막 줄부터 거꾸로 출력한다.

# 최신 로그가 아래에 쌓이는 파일을 역순으로 보기
tac /var/log/auth.log | head -20

less — 페이지 단위 탐색

less는 파일 내용을 페이지 단위로 스크롤하며 읽을 수 있는 뷰어(pager)이다. more라는 오래된 명령어의 개선판이며, 이름은 "less is more"라는 말장난에서 유래했다.

less /var/log/syslog
less +G /var/log/syslog    # 파일 끝부터 열기

less 내부 조작 키

less는 열린 상태에서 다양한 키로 탐색할 수 있다. 외울 필요 없이, 자주 쓰는 것만 알면 된다:

키 동작
Space / f 한 페이지 아래로
b 한 페이지 위로
j / k 한 줄 아래 / 위로
G 파일 끝으로 이동
g 파일 처음으로 이동
/키워드 아래 방향으로 검색
?키워드 위 방향으로 검색
n 다음 검색 결과
N 이전 검색 결과
q 종료
&패턴 패턴이 포함된 줄만 표시 (필터)

실무 팁: less의 / 검색은 로그 파일에서 특정 에러 메시지를 찾을 때 매우 유용하다. &ERROR를 입력하면 "ERROR"가 포함된 줄만 필터링하여 볼 수 있다.

more와의 차이

more는 앞으로만 스크롤할 수 있고, less는 앞뒤로 자유롭게 이동할 수 있다. 사실상 less만 사용한다고 보면 된다.


head와 tail — 파일의 앞/뒤 확인

head — 파일 앞부분

# 기본: 처음 10줄 출력
head /etc/passwd

# 줄 수 지정
head -n 20 /var/log/syslog
head -20 /var/log/syslog       # 동일 (축약형)

# 바이트 수 지정
head -c 100 binary_file        # 처음 100바이트

tail — 파일 뒷부분

# 기본: 마지막 10줄 출력
tail /var/log/syslog

# 줄 수 지정
tail -n 50 /var/log/syslog
tail -50 /var/log/syslog       # 동일

# 특정 줄부터 끝까지 (+N: N번째 줄부터)
tail -n +100 /etc/passwd       # 100번째 줄부터 끝까지

tail -f — 실시간 로그 모니터링 ★★★

tail -f는 가장 자주 사용하는 명령어 조합 중 하나이다. 파일에 새로운 내용이 추가되면 실시간으로 화면에 표시한다.

# 실시간 로그 모니터링
tail -f /var/log/syslog

# 여러 파일 동시 모니터링
tail -f /var/log/nginx/access.log /var/log/nginx/error.log

# 특정 키워드만 필터링하며 모니터링
tail -f /var/log/syslog | grep --line-buffered "error"
  • f vs F의 차이:
옵션 동작
-f 파일 디스크립터를 추적한다. 파일이 삭제되고 재생성되면 추적이 끊긴다.
-F 파일 이름을 추적한다. 로그 로테이션으로 파일이 교체되어도 계속 추적한다.

실무에서는 로그 로테이션(logrotate)이 적용된 환경이 대부분이므로, tail -F를 사용하는 것이 더 안전하다.

# 로그 로테이션 환경에서 안전한 모니터링
tail -F /var/log/nginx/access.log

파일 내용 가공 출력

cut — 필드/컬럼 추출

cut은 텍스트에서 특정 필드(열)만 잘라내는 명령어이다. CSV나 구분자 기반 파일을 다룰 때 유용하다.

# /etc/passwd에서 사용자명(1번째 필드)만 추출
# /etc/passwd는 : 으로 필드가 구분된다
cut -d ':' -f 1 /etc/passwd

# 1번, 3번 필드 (사용자명, UID)
cut -d ':' -f 1,3 /etc/passwd

# 1~4번 필드 (범위)
cut -d ':' -f 1-4 /etc/passwd

# CSV 파일에서 2번째 컬럼 추출
cut -d ',' -f 2 data.csv

# 문자 위치 기준으로 추출 (고정 폭 데이터)
cut -c 1-10 fixed_width.txt    # 1~10번째 문자

주요 옵션:

  • d : 구분자(delimiter) 지정 (기본값: TAB)
  • f : 추출할 필드 번호
  • c : 추출할 문자 위치

tr — 문자 변환/삭제

Translate의 약자이다. 문자를 다른 문자로 치환하거나 삭제한다. 주의할 점은, tr은 파일을 직접 읽지 못하고 반드시 표준 입력(stdin)으로 데이터를 받아야 한다.

# 소문자 → 대문자 변환
echo "hello world" | tr 'a-z' 'A-Z'
# HELLO WORLD

# 공백을 줄바꿈으로 변환 (단어를 한 줄에 하나씩)
echo "one two three" | tr ' ' '\n'

# 특정 문자 삭제 (-d)
echo "Hello, World! 123" | tr -d '0-9'
# Hello, World!

# 연속된 중복 문자를 하나로 압축 (-s: squeeze)
echo "hello     world" | tr -s ' '
# hello world

# 실무: 로그에서 탭을 쉼표로 변환 (TSV → CSV)
cat data.tsv | tr '\t' ',' > data.csv

nl — 줄 번호 추가

# 줄 번호를 붙여서 출력 (빈 줄 제외)
nl /etc/ssh/sshd_config

# 빈 줄에도 번호 부여
nl -ba /etc/ssh/sshd_config

표준 스트림 (Standard Streams)

리눅스의 모든 프로세스는 실행될 때 3개의 기본 스트림을 자동으로 부여받는다:

┌─────────────────────────────────────────────────┐
│                  프로세스                         │
│                                                 │
│  stdin (fd 0)  ──→  [처리]  ──→  stdout (fd 1)   │
│                            ──→  stderr (fd 2)   │
└─────────────────────────────────────────────────┘
스트림 파일 디스크립터(fd) 설명 기본 연결
stdin (표준 입력) 0 프로세스가 데이터를 읽어오는 통로 키보드
stdout (표준 출력) 1 프로세스가 정상 결과를 내보내는 통로 터미널 화면
stderr (표준 에러) 2 프로세스가 에러 메시지를 내보내는 통로 터미널 화면

파일 디스크립터(File Descriptor, fd)란 커널이 열린 파일(스트림 포함)을 관리하기 위해 부여하는 정수 번호이다. 0, 1, 2는 예약된 번호이고, 이후 열리는 파일은 3, 4, 5... 순서로 번호가 부여된다.

왜 stdout과 stderr가 분리되어 있는가:

정상 출력과 에러 메시지를 독립적으로 처리할 수 있기 때문이다.

# 정상 출력은 파일에 저장하고, 에러만 화면에 표시
find / -name "*.conf" > result.txt 2>&1
# 1(stdout) → result.txt
# 2(stderr) → 화면에 표시 (권한 없는 디렉터리 접근 에러 등)

# 에러 메시지만 파일에 저장
find / -name "*.conf" 2> errors.txt

# 에러를 아예 무시
find / -name "*.conf" 2>/dev/null

grep — 패턴으로 텍스트 검색

grep은 Global Regular Expression Print의 약자이다. 파일에서 특정 패턴(문자열)이 포함된 줄을 검색하여 출력한다. 가장 많이 사용되는 명령어 중 하나이며, 로그 분석과 트러블슈팅의 핵심 도구이다.

기본 사용법

# 파일에서 문자열 검색
grep "error" /var/log/syslog

# 대소문자 무시 (-i)
grep -i "error" /var/log/syslog

# 줄 번호 함께 표시 (-n)
grep -n "error" /var/log/syslog

# 매치된 줄 수만 출력 (-c)
grep -c "error" /var/log/syslog

# 패턴이 포함되지 않은 줄만 출력 (-v: invert)
grep -v "^#" /etc/ssh/sshd_config     # 주석(#) 제외

# 디렉터리 내 모든 파일에서 재귀 검색 (-r)
grep -r "database_url" /etc/myapp/

# 매치된 파일명만 출력 (-l)
grep -rl "TODO" ./src/

주변 줄 함께 보기 (Context)

에러 로그를 검색할 때, 에러가 발생한 줄만 보면 맥락을 파악하기 어렵다. 주변 줄을 함께 보면 원인을 파악하기 쉽다.

# 매치된 줄 + 아래 3줄 (-A: After)
grep -A 3 "Exception" /var/log/app.log

# 매치된 줄 + 위 3줄 (-B: Before)
grep -B 3 "Exception" /var/log/app.log

# 매치된 줄 + 위아래 3줄 (-C: Context)
grep -C 3 "Exception" /var/log/app.log

자주 쓰는 패턴

# 설정 파일에서 주석과 빈 줄 제거하고 실제 설정만 보기
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"

# 로그에서 특정 시간대의 에러 검색
grep "2025-03-23 14:" /var/log/syslog | grep -i "error"

# 특정 IP의 접속 로그 검색
grep "192.168.1.100" /var/log/nginx/access.log

# 프로세스 목록에서 특정 프로세스 찾기
ps aux | grep nginx | grep -v grep

요약

명령어 용도 핵심 포인트
cat 짧은 파일 전체 출력, 파일 연결 긴 파일에는 부적합
less 긴 파일 페이지 탐색 /로 검색, &로 필터
head 파일 앞부분 확인 -n N으로 줄 수 지정
tail 파일 뒷부분 확인 -F로 실시간 모니터링
cut 필드/컬럼 추출 -d(구분자) + -f(필드)
tr 문자 변환/삭제 stdin으로만 입력 받음
grep 패턴 검색 -i, -r, -v, -C 가 핵심
strings 바이너리에서 텍스트 추출 파일 정체 파악에 유용

Chapter 05. 링크 (심볼릭 링크, 하드 링크)

리눅스에서 링크(Link)란 하나의 파일에 대해 여러 이름(경로)을 부여하는 메커니즘이다. Windows의 "바로가기"와 유사하지만, 동작 방식이 근본적으로 다르다.

  • 파일의 실제 데이터와 메타데이터는 inode에 저장된다
  • 파일 이름은 inode에 저장되지 않는다
  • 디렉터리란 "파일명 → inode 번호"의 매핑 테이블이다
디렉터리 엔트리 (매핑 테이블)
┌──────────────────────────────┐
│  파일명         → inode 번호    │
│  config.yaml   → 131074      │
│  readme.md     → 131075      │
│  deploy.sh     → 131076      │
└──────────────────────────────┘

inode 테이블
┌──────────────────────────────────────────┐
│  inode 131074: 권한, 소유자, 크기, 데이터 위치  │
│  inode 131075: 권한, 소유자, 크기, 데이터 위치  │
│  inode 131076: 권한, 소유자, 크기, 데이터 위치  │
└──────────────────────────────────────────┘

링크란 이 매핑 관계를 추가로 만드는 것이다.


하드 링크 (Hard Link)

하드 링크는 동일한 inode를 가리키는 새로운 디렉터리 엔트리를 만드는 것이다. 원본과 하드 링크는 완전히 동등한 관계이며, 어느 쪽이 "원본"이고 어느 쪽이 "링크"인지 구분할 수 없다.

원본 생성 후:
  "config.yaml"  ──→  inode 131074  ──→  [디스크의 실제 데이터]
                       (Links: 1)

하드 링크 생성 후:
  "config.yaml"  ──→  inode 131074  ──→  [디스크의 실제 데이터]
  "config.bak"   ──→  inode 131074  ──→  (같은 데이터를 가리킴)
                       (Links: 2)
  • 두 파일명이 동일한 inode(동일한 데이터)를 가리킨다
  • 어느 쪽을 수정해도 양쪽 모두 반영된다 (같은 데이터이므로)
  • 한쪽을 삭제해도 다른 쪽은 영향 없다 (inode의 링크 카운트가 0이 되어야 데이터가 삭제된다)
  • 디스크 공간을 추가로 차지하지 않는다 (데이터 복제가 아니므로)

생성 및 확인

# 하드 링크 생성
ln original.txt hardlink.txt

# inode 번호 확인 — 동일한 번호를 가진다
ls -li original.txt hardlink.txt
# 131074 -rw-r--r-- 2 devops devops 1234 Mar 23 10:00 hardlink.txt
# 131074 -rw-r--r-- 2 devops devops 1234 Mar 23 10:00 original.txt
#   │                 │
#   └ 같은 inode      └ Links: 2 (하드 링크 수)

# 한쪽 수정 → 양쪽 반영 확인
echo "new content" >> original.txt
cat hardlink.txt    # "new content"가 보인다

# 한쪽 삭제 → 다른 쪽은 살아있다
rm original.txt
cat hardlink.txt    # 여전히 정상 접근 가능
ls -li hardlink.txt
# 131074 -rw-r--r-- 1 devops devops ...    ← Links가 2→1로 줄어듦

제약사항

제약 이유
디렉터리에는 하드 링크를 만들 수 없다 순환 참조(circular reference)가 발생하면 파일시스템이 무한 루프에 빠질 수 있다
다른 파일시스템(파티션)을 넘어서 만들 수 없다 inode 번호는 파일시스템 내에서만 유일하다. 다른 파일시스템의 inode와는 연결할 수 없다

심볼릭 링크 (Symbolic Link / Symlink)

심볼릭 링크는 다른 파일의 경로(문자열)를 저장하는 별도의 파일이다. 하드 링크와 달리 자체 inode를 가지며, 그 안에 "원본 파일의 경로"를 텍스트로 저장한다.

심볼릭 링크 생성 후:
  "config.yaml"       ──→  inode 131074  ──→  [실제 데이터]
  "config-link.yaml"  ──→  inode 131099  ──→  "/home/devops/config.yaml" (경로 문자열)
                             (타입: symlink)

Windows의 "바로가기"와 가장 유사한 개념이다. 다만 리눅스의 심볼릭 링크는 OS 수준에서 투명하게 동작하므로, 대부분의 프로그램이 심볼릭 링크를 원본 파일처럼 취급한다.

생성 및 확인

# 심볼릭 링크 생성 (-s 옵션)
ln -s /etc/nginx/nginx.conf ~/nginx-config

# 확인
ls -la ~/nginx-config
# lrwxrwxrwx 1 devops devops 21 Mar 23 10:00 nginx-config -> /etc/nginx/nginx.conf
# │                            │                              │
# └ 타입: l (심볼릭 링크)        └ 링크 파일 자체의 크기           └ 가리키는 원본 경로
#                                (경로 문자열의 길이)

# 심볼릭 링크를 통해 원본 파일 읽기
cat ~/nginx-config    # /etc/nginx/nginx.conf의 내용이 출력된다

# 디렉터리에도 심볼릭 링크 생성 가능
ln -s /var/log/nginx ~/logs
ls ~/logs/            # /var/log/nginx/의 내용이 보인다

# 다른 파일시스템(파티션)을 넘어서도 생성 가능
ln -s /mnt/external/data ~/external-data

끊어진 심볼릭 링크 (Dangling Symlink)

심볼릭 링크의 가장 큰 약점은 원본이 삭제되면 링크가 끊어진다는 것이다. 끊어진 심볼릭 링크를 dangling symlink이라고 한다.

# 원본 생성 → 심볼릭 링크 생성 → 원본 삭제
touch /tmp/original.txt
ln -s /tmp/original.txt ~/my-link
rm /tmp/original.txt

# 끊어진 링크 — 접근하면 에러
cat ~/my-link
# cat: /home/devops/my-link: No such file or directory

# ls에서 끊어진 링크는 빨간색으로 표시된다 (색상 지원 터미널)
ls -la ~/my-link
# lrwxrwxrwx 1 devops devops 17 Mar 23 10:00 my-link -> /tmp/original.txt (빨간색)

# 끊어진 심볼릭 링크 찾기
find /home -type l ! -exec test -e {} \; -print

실무에서의 심볼릭 링크 활용

Nginx 사이트 활성화/비활성화

Nginx의 가상 호스트 관리는 심볼릭 링크의 대표적 활용 사례이다.

# 사이트 설정은 sites-available에 저장
/etc/nginx/sites-available/mysite.conf    # 설정 파일 (원본)

# 활성화: sites-enabled에 심볼릭 링크 생성
sudo ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/

# 비활성화: 심볼릭 링크만 삭제 (원본은 보존)
sudo rm /etc/nginx/sites-enabled/mysite.conf

장점: 설정 파일 자체를 삭제하지 않고도 사이트를 활성화/비활성화할 수 있다.

무중단 배포 (Zero-Downtime Deployment)

# 디렉터리 구조
/opt/myapp/
├── releases/
│   ├── v1.0.0/          # 이전 버전
│   ├── v1.1.0/          # 이전 버전
│   └── v1.2.0/          # 새 버전
└── current -> releases/v1.1.0   # 현재 운영 중인 버전 (심볼릭 링크)

# 배포: 심볼릭 링크만 교체 (거의 즉시 완료)
ln -sfn /opt/myapp/releases/v1.2.0 /opt/myapp/current
#  -s: 심볼릭 링크
#  -f: 기존 링크 덮어쓰기
#  -n: 대상이 디렉터리여도 링크 자체를 교체 (안으로 들어가지 않음)

# 롤백: 이전 버전으로 링크만 되돌리기 (즉시 완료)
ln -sfn /opt/myapp/releases/v1.1.0 /opt/myapp/current

웹 서버의 DocumentRoot가 /opt/myapp/current를 가리키고 있다면, 심볼릭 링크 교체만으로 배포와 롤백이 거의 즉시 이루어진다.


요약

개념 핵심 내용
하드 링크 동일한 inode를 공유, 원본 삭제해도 데이터 유지, 같은 파티션만 가능
심볼릭 링크 별도 inode, 경로 문자열 저장, 파티션/디렉터리 제약 없음, 원본 삭제 시 끊어짐
실무 기본 선택 심볼릭 링크 (99%의 경우)
핵심 활용 Nginx sites-enabled, 무중단 배포, 바이너리 버전 관리
생성 명령어 ln (하드), ln -s (심볼릭), ln -sfn (덮어쓰기)
주의사항 심볼릭 링크 디렉터리 삭제 시 / 붙이지 않기

Chapter 06. 압축 & 아카이브

아카이브와 압축의 차이

아카이브

여러 파일과 디렉터리를 하나의 파일로 묶는 것이다. 파일의 크기를 줄이지는 않는다. 마치 여러 서류를 하나의 봉투에 넣는 것과 같다.

압축

데이터의 크기를 줄이는 것이다. 반복되는 패턴을 효율적으로 인코딩하여 파일 크기를 감소시킨다.

[파일A] [파일B] [파일C]
         │
    아카이브 (tar)
         ↓
  [파일A+B+C.tar]        ← 크기는 거의 동일 (묶기만 함)
         │
      압축 (gzip)
         ↓
  [파일A+B+C.tar.gz]     ← 크기가 줄어듦

tar — 아카이브 도구

Tape Archive의 약자이다. 원래 자기 테이프에 백업하기 위해 만들어졌지만, 현재는 파일 묶기/풀기의 표준 도구이다.

tar의 옵션은 동작(무엇을 할 것인가)과 수식(어떻게 할 것인가)으로 나뉜다:

동작 옵션 설명
-c Create — 새 아카이브 생성
-x Extract — 아카이브 풀기
-t lisT — 아카이브 내용 목록 보기
수식 옵션 설명
-f File — 아카이브 파일명 지정 (거의 항상 사용)
-v Verbose — 처리 과정 출력
-z gzip으로 압축/해제 (.tar.gz, .tgz)
-j bzip2로 압축/해제 (.tar.bz2)
-J xz로 압축/해제 (.tar.xz)
-C 지정한 디렉터리에서 작업

아카이브 생성

# 기본 아카이브 생성 (압축 없이 묶기만)
tar -cvf archive.tar file1.txt file2.txt dir1/
#  -c: 생성
#  -v: 과정 출력
#  -f: 파일명 지정

# gzip 압축 아카이브 (가장 흔히 사용) ★★★
tar -czvf archive.tar.gz /var/log/nginx/

# bzip2 압축 아카이브 (더 높은 압축률, 더 느림)
tar -cjvf archive.tar.bz2 /var/log/nginx/

# xz 압축 아카이브 (가장 높은 압축률, 가장 느림)
tar -cJvf archive.tar.xz /var/log/nginx/

# 특정 파일/디렉터리 제외
tar -czvf backup.tar.gz --exclude='*.log' --exclude='.git' /opt/myapp/
tar -czvf backup.tar.gz --exclude-vcs /opt/myapp/   # VCS 디렉터리 전체 제외

아카이브 풀기

# gzip 압축 아카이브 풀기
tar -xzvf archive.tar.gz

# 특정 디렉터리에 풀기 (-C 옵션)
tar -xzvf archive.tar.gz -C /opt/restore/

# 아카이브 내용 목록 보기 (풀지 않고 확인)
tar -tzvf archive.tar.gz

# 아카이브에서 특정 파일만 추출
tar -xzvf archive.tar.gz path/to/specific/file.txt

실무 패턴

# 서버 설정 백업 (날짜 포함)
tar -czvf /backup/etc-backup-$(date +%Y%m%d).tar.gz /etc/

# 애플리케이션 배포 패키지 생성 (불필요한 파일 제외)
tar -czvf release-v1.2.0.tar.gz \
  --exclude='node_modules' \
  --exclude='.env' \
  --exclude='*.log' \
  ./myapp/

# 원격 서버로 직접 전송 (로컬에 파일을 만들지 않고)
tar -czf - /opt/myapp/ | ssh user@remote "tar -xzf - -C /opt/"
# '-'는 stdout/stdin을 의미한다

압축 도구 비교

도구 확장자 압축률 속도 특징
gzip .gz 보통 빠름 가장 범용적, 사실상 표준
bzip2 .bz2 높음 느림 gzip보다 높은 압축률
xz .xz 매우 높음 매우 느림 배포판 패키지에서 자주 사용
zstd .zst 높음 매우 빠름 최신, 압축률과 속도 모두 우수
lz4 .lz4 낮음 극히 빠름 실시간 압축에 적합

선택 기준:

  • 일반적인 백업/전송: gzip (호환성 최고)
  • 대용량 로그 아카이브: xz 또는 zstd (높은 압축률)
  • 빠른 처리가 중요한 경우: zstd 또는 lz4

gzip / gunzip

# 파일 압축 (원본 파일이 .gz로 대체된다)
gzip access.log
# access.log → access.log.gz (원본 사라짐)

# 원본 유지하면서 압축
gzip -k access.log
# access.log 유지, access.log.gz 생성

# 해제
gunzip access.log.gz
# 또는
gzip -d access.log.gz

# 압축률 조절 (1=빠름/낮은압축, 9=느림/높은압축, 기본=6)
gzip -9 large_file.log    # 최대 압축

# 압축 파일의 내용을 해제하지 않고 보기
zcat access.log.gz        # cat처럼 출력
zless access.log.gz       # less처럼 페이지 단위
zgrep "error" access.log.gz  # grep처럼 검색

xz / unxz

# 압축
xz large_file.log

# 원본 유지하면서 압축
xz -k large_file.log

# 해제
unxz large_file.log.xz

# 멀티스레드 압축 (속도 개선) ★
xz -T 0 large_file.log    # 사용 가능한 모든 코어 활용

# 압축 파일 내용 보기
xzcat large_file.log.xz

zip / unzip

zip은 Windows 환경과의 호환성을 위해 사용한다. 리눅스 자체적으로는 tar.gz가 표준이지만, Windows 사용자에게 파일을 전달하거나 받을 때 zip을 사용하게 된다.

# 설치 (없는 경우)
sudo apt install zip unzip

# 압축 (파일/디렉터리)
zip -r archive.zip mydir/
zip archive.zip file1.txt file2.txt

# 해제
unzip archive.zip
unzip archive.zip -d /opt/extract/    # 특정 디렉터리에 풀기

# 내용 목록 보기
unzip -l archive.zip

# 특정 파일만 추출
unzip archive.zip path/to/file.txt

# 비밀번호 설정 압축
zip -e -r secret.zip sensitive_data/

압축 알고리즘의 원리

무손실 압축(Lossless Compression)은 데이터에서 반복되는 패턴을 찾아서 더 짧은 표현으로 대체한다. 해제하면 원본과 100% 동일한 데이터가 복원된다.

예시 — AAAAABBBCC라는 10바이트 데이터:

  • 압축 후: 5A3B2C (6바이트) — "A가 5번, B가 3번, C가 2번"
  • 이를 Run-Length Encoding (RLE)이라고 한다

실제 gzip, bzip2, xz 등은 이보다 훨씬 정교한 알고리즘을 사용하지만, 핵심 원리는 동일하다 — 반복과 패턴을 효율적으로 인코딩하는 것이다.


요약

도구 역할 핵심 사용법
tar 아카이브(묶기/풀기) -czf(생성), -xzf(풀기), -tzf(목록)
gzip 범용 압축 gzip file, zcat, zgrep
xz 고압축 xz -T0 file (멀티스레드)
zip/unzip Windows 호환 zip -r, unzip -l
상황 추천
리눅스 서버 간 백업/전송 tar.gz
장기 아카이브 (공간 절약) tar.xz
Windows 사용자에게 전달 zip
압축된 로그 검색 zgrep, zcat, zless
서버 간 실시간 전송 `tar -czf -

Chapter 07. 권한 & 소유자 관리

리눅스는 태생적으로 멀티유저(multi-user) 시스템이다. 여러 사용자가 동시에 접속하여 작업하기 때문에, "누가 어떤 파일을 읽고, 쓰고, 실행할 수 있는가"를 제어하는 것이 필수이다.

권한 문제는 매우 빈번하게 발생할 수 있다

  • 배포 스크립트가 실행 권한이 없어서 실패
  • 애플리케이션이 로그 파일에 쓰기 권한이 없어서 에러
  • 설정 파일이 누구나 읽을 수 있어서 보안 위험 (DB 비밀번호 노출 등)
  • Docker 컨테이너 내부의 파일 소유자 문제

권한의 구조

세 가지 주체 (Who)

리눅스는 파일에 접근하는 주체를 세 그룹으로 나눈다:

주체 약자 설명
Owner (소유자) u (user) 파일을 소유한 사용자. 보통 파일을 생성한 사람이다.
Group (그룹) g 파일에 지정된 그룹에 속한 사용자들.
Others (기타) o 소유자도 아니고 그룹에도 속하지 않는 나머지 모든 사용자.

세 가지 권한

권한 문자 숫자 파일에 대한 의미 디렉터리에 대한 의미
Read r 4 파일 내용을 읽을 수 있다 디렉터리 내 파일 목록을 볼 수 있다 (ls)
Write w 2 파일 내용을 수정할 수 있다 디렉터리 내 파일을 생성/삭제할 수 있다
Execute x 1 파일을 실행할 수 있다 디렉터리에 진입할 수 있다 (cd)

디렉터리의 x(실행) 권한은 직관적이지 않으므로 주의가 필요하다:

  • r 없이 x만 있으면: 디렉터리 안의 파일 목록은 볼 수 없지만, 파일명을 정확히 알면 접근할 수 있다
  • x 없이 r만 있으면: 파일 목록은 볼 수 있지만, 실제로 파일에 접근하거나 cd로 진입할 수 없다
  • w는 x와 함께 있어야 의미가 있다: 디렉터리에 진입(x)할 수 있어야 파일을 생성/삭제(w)할 수 있다

권한 표기법

ls -l 출력에서 권한은 9자리 문자로 표시된다:

-rwxr-xr--
│├─┤├─┤├─┤
│ │  │  └── Others: r-- (읽기만)
│ │  └── Group: r-x (읽기+실행)
│ └── Owner: rwx (읽기+쓰기+실행)
└── 파일 타입 (- = 일반 파일)

8진수(Octal) 표기법

각 권한을 숫자로 표현하며, 세 자리 숫자로 소유자/그룹/기타의 권한을 나타낸다.

r=4, w=2, x=1 → 합산하여 표현

rwx = 4+2+1 = 7
r-x = 4+0+1 = 5
r-- = 4+0+0 = 4
--- = 0+0+0 = 0

자주 사용하는 권한 조합:

8진수 문자 표기 의미 용도
755 rwxr-xr-x 소유자 전체, 나머지 읽기+실행 실행 파일, 디렉터리
644 rw-r--r-- 소유자 읽기+쓰기, 나머지 읽기 일반 파일, 설정 파일
700 rwx------ 소유자만 전체 권한 개인 디렉터리, SSH 키 디렉터리
600 rw------- 소유자만 읽기+쓰기 SSH 개인 키, 민감한 설정
777 rwxrwxrwx 모두에게 전체 권한 보안 위험 — 거의 사용하지 않는다
400 r-------- 소유자만 읽기 AWS 키 파일 등

chmod — 권한 변경

Change Mode의 약자이다.

8진수 방식

# 파일 권한을 644로 설정
chmod 644 config.yaml

# 스크립트에 실행 권한 부여
chmod 755 deploy.sh

# SSH 개인 키 — 소유자만 읽기 (AWS에서 필수)
chmod 400 my-key.pem

# 디렉터리와 내용물에 재귀적으로 적용
chmod -R 755 /var/www/html/

심볼릭 방식

누구(u/g/o/a)에게 무엇(r/w/x)을 어떻게(+/-/=) 할 것인지를 문자로 표현한다.

기호 의미
u owner(소유자)
g group(그룹)
o others(기타)
a all(전체) — u+g+o
+ 권한 추가
- 권한 제거
= 권한을 정확히 설정 (기존 권한 대체)
# 소유자에게 실행 권한 추가
chmod u+x script.sh

# 그룹과 기타에서 쓰기 권한 제거
chmod go-w sensitive.conf

# 기타 사용자의 모든 권한 제거
chmod o= secret.env

# 모든 사용자에게 읽기 권한 부여
chmod a+r public.html

# 실행 권한만 추가 (기존 권한 유지)
chmod +x deploy.sh

chown — 소유자/그룹 변경

Change Owner의 약자이다. 파일의 소유자와 소유 그룹을 변경한다. root 권한(sudo)이 필요하다.

# 소유자 변경
sudo chown nginx /var/www/html/index.html

# 소유자 + 그룹 동시 변경
sudo chown nginx:www-data /var/www/html/index.html

# 그룹만 변경 (: 앞을 비움)
sudo chown :www-data /var/www/html/index.html

# 재귀적으로 변경 (디렉터리 전체)
sudo chown -R nginx:www-data /var/www/html/

# 심볼릭 링크 자체의 소유자 변경 (기본은 대상 파일 변경)
sudo chown -h devops symlink_file

chgrp — 그룹만 변경

# chown :group과 동일한 효과
sudo chgrp www-data /var/www/html/
sudo chgrp -R docker /opt/containers/

특수 권한

기본 rwx 외에 세 가지 특수 권한이 있다.

SUID (Set User ID) — 4000

실행 파일에 SUID가 설정되면, 해당 파일을 누가 실행하든 파일 소유자의 권한으로 실행된다.

# 대표적인 SUID 파일
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 ... /usr/bin/passwd
#    ^
#    s = SUID가 설정되어 있다는 표시

어떤 상황에 필요할까?
passwd 명령어는 /etc/shadow 파일을 수정해야 한다. 이 파일은 root만 쓸 수 있다. 하지만 일반 사용자도 자신의 비밀번호를 변경할 수 있어야 한다. SUID를 통해 일반 사용자가 passwd를 실행하면 root 권한으로 동작하여 /etc/shadow를 수정할 수 있게 된다.

# SUID 설정
chmod u+s executable
chmod 4755 executable

# 보안 감사 — SUID 파일 찾기 (비정상적인 SUID 파일은 보안 위험)
find / -type f -perm -4000 2>/dev/null

SGID (Set Group ID) — 2000

파일에 설정: 실행 시 파일 소유 그룹의 권한으로 실행된다.

디렉터리에 설정: 해당 디렉터리 안에서 생성되는 새 파일의 그룹이 디렉터리의 그룹을 상속한다. 팀 공유 디렉터리에서 매우 유용하다.

# 팀 공유 디렉터리 설정
sudo mkdir /shared/project
sudo chown :devteam /shared/project
sudo chmod 2775 /shared/project
#          ^
#          2 = SGID

# 이후 이 디렉터리에서 생성되는 모든 파일은 자동으로 devteam 그룹 소유

Sticky Bit — 1000

디렉터리에 설정하면, 해당 디렉터리 안의 파일을 파일의 소유자와 root만 삭제할 수 있다. 다른 사용자의 파일을 삭제할 수 없게 보호한다.

# /tmp의 권한을 확인해보면 Sticky Bit가 설정되어 있다
ls -ld /tmp
# drwxrwxrwt 15 root root 4096 ... /tmp
#          ^
#          t = Sticky Bit

/tmp는 모든 사용자가 읽고 쓸 수 있는(rwxrwxrwx) 디렉터리이다. Sticky Bit가 없으면 사용자 A가 사용자 B의 임시 파일을 삭제할 수 있어 위험하다. Sticky Bit 덕분에 자기 파일만 삭제할 수 있다.

# Sticky Bit 설정
chmod +t /shared/tmp
chmod 1777 /shared/tmp

특수 권한 정리

특수 권한 숫자 대상 효과
SUID 4000 파일 실행 시 소유자 권한으로 동작
SGID 2000 디렉터리 새 파일이 디렉터리의 그룹을 상속
Sticky Bit 1000 디렉터리 소유자만 자기 파일 삭제 가능

umask — 기본 권한 설정

umask는 새로 생성되는 파일과 디렉터리의 기본 권한을 결정하는 마스크 값이다.

리눅스에서 파일/디렉터리 생성 시 기본 최대 권한:

  • 파일: 666 (rw-rw-rw-) — 보안상 실행 권한은 기본 부여하지 않는다
  • 디렉터리: 777 (rwxrwxrwx)

여기서 umask 값을 빼면 실제 생성되는 파일의 권한이 된다:

파일 기본 권한   = 666 - umask
디렉터리 기본 권한 = 777 - umask
# 현재 umask 확인
$ umask
0022

# umask가 0022일 때:
# 파일:      666 - 022 = 644 (rw-r--r--)
# 디렉터리:   777 - 022 = 755 (rwxr-xr-x)

# umask 변경
umask 0077
# 파일:      666 - 077 = 600 (rw-------)
# 디렉터리:   777 - 077 = 700 (rwx------)
# → 소유자만 접근 가능하게 된다

보안이 중요한 환경에서는 umask를 0027 또는 0077로 설정하여 기타 사용자의 접근을 기본적으로 차단한다. umask 설정은 ~/.bashrc나 /etc/profile에 넣어 영구 적용할 수 있다.

참고: umask는 엄밀히는 단순 뺄셈이 아닌 비트 마스크(NOT AND) 연산이다. 대부분의 경우 뺄셈과 결과가 같지만, 이론적으로는 최대권한 AND (NOT umask)가 정확한 계산이다.


sudo — 관리자 권한 실행

sudo는 Superuser Do의 약자이다. 일반 사용자가 임시로 root 권한을 빌려서 명령어를 실행할 수 있게 한다. root 계정으로 직접 로그인하는 것보다 안전하다.

왜 root 직접 로그인 대신 sudo를 사용하는가:

  • 감사 로그: 누가, 언제, 어떤 명령어를 실행했는지 기록된다 (/var/log/auth.log)
  • 최소 권한 원칙: 필요한 순간에만 일시적으로 권한을 상승시킨다
  • 실수 방지: 항상 root로 작업하면 한 번의 실수가 시스템 전체에 영향을 미친다
# root 권한으로 명령어 실행
sudo systemctl restart nginx

# root 셸로 전환
sudo -i       # root의 로그인 환경으로 전환
sudo su -     # 위와 유사

# 다른 사용자로 명령어 실행
sudo -u nginx cat /etc/nginx/nginx.conf

# 직전 명령어를 sudo로 재실행 ★
sudo !!
# 예: apt update → 권한 에러 → sudo !!로 재실행

요약

명령어 용도 핵심
chmod 권한 변경 755(8진수), u+x(심볼릭)
chown 소유자/그룹 변경 -R(재귀), root 권한 필요
umask 기본 권한 마스크 0022(기본), 0077(보안 강화)
sudo 관리자 권한 실행 visudo로 설정, !!로 재실행

Chapter 08. 디스크 & 용량 관리

디스크 관리가 중요한 이유

클라우드/서버 환경에서 "디스크 용량 부족"은 가장 빈번하게 발생하는 장애 원인 중 하나이다. 디스크가 꽉 차면 다음과 같은 문제가 발생한다:

  • 로그를 더 이상 기록할 수 없어서 애플리케이션이 비정상 종료
  • 데이터베이스가 쓰기를 멈추거나 손상
  • 시스템 자체가 부팅 불가 상태에 빠짐
  • 배포(deploy)가 실패

디스크 구조 기본 개념

물리 디스크 → 파티션 → 파일시스템

물리 디스크 (/dev/sda 또는 /dev/nvme0n1)
  ├── 파티션 1 (/dev/sda1) → 파일시스템(ext4) → / (루트)에 마운트
  ├── 파티션 2 (/dev/sda2) → 파일시스템(ext4) → /home에 마운트
  └── 파티션 3 (/dev/sda3) → 스왑(swap)

파티션(Partition): 하나의 물리 디스크를 논리적으로 나눈 영역이다. 각 파티션은 독립적으로 포맷하고 마운트할 수 있다.

파일시스템(Filesystem): 파티션 위에 생성되는 데이터 저장 구조이다. 포맷(format)이란 파티션에 파일시스템을 생성하는 작업이다.

마운트(Mount): 파일시스템을 디렉터리 트리의 특정 위치에 연결하는 것이다.


디스크 용량 확인

df — 파일시스템 단위 용량 확인

Disk Free의 약자이다. 마운트된 파일시스템별 전체/사용/남은 용량을 표시한다.

# 기본 사용 (사람이 읽기 쉬운 형태) ★★★
df -h
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda1        50G   32G   16G  67% /
# /dev/sda2       100G   45G   50G  48% /home
# tmpfs            3.9G  1.2M  3.9G   1% /run

# 파일시스템 타입도 함께 표시
df -hT
# Filesystem      Type  Size  Used Avail Use% Mounted on
# /dev/sda1       ext4   50G   32G   16G  67% /

# 특정 경로가 어느 파일시스템에 속하는지 확인
df -h /var/log/
# → /var/log/가 위치한 파일시스템의 용량 정보

# inode 사용량 확인 ★ (파일 수 관련 문제 진단)
df -i
# Filesystem      Inodes  IUsed   IFree IUse% Mounted on
# /dev/sda1     3276800 234567 3042233    8% /

df는 파일시스템 단위로 보여준다. "어느 파티션이 꽉 찼는가"를 파악하는 첫 번째 단계이다.

du — 디렉터리/파일 단위 용량 확인

Disk Usage의 약자이다. df로 어느 파티션이 문제인지 파악했다면, du로 어떤 디렉터리가 공간을 많이 차지하는지 추적한다.

# 현재 디렉터리의 총 용량
du -sh .

# 하위 디렉터리별 용량 (1단계)
du -h --max-depth=1 /var/

# 용량 순 정렬 (큰 것부터) ★★★
du -sh /var/*/ 2>/dev/null | sort -rh | head -10

# 특정 디렉터리의 총 용량
du -sh /var/log/ /var/cache/ /var/lib/

# 파일 단위까지 표시
du -ah /var/log/ | sort -rh | head -20

lsblk — 블록 디바이스 목록

시스템에 연결된 디스크와 파티션의 트리 구조를 보여준다.

$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    0   50G  0 disk
├─sda1        8:1    0   49G  0 part /
└─sda2        8:2    0    1G  0 part [SWAP]
nvme0n1     259:0    0  100G  0 disk
└─nvme0n1p1 259:1    0  100G  0 part /data

# 파일시스템 정보 포함
lsblk -f
# NAME    FSTYPE LABEL UUID                                 MOUNTPOINT
# sda1    ext4         a1b2c3d4-...                         /

디스크 용량 문제 해결

"디스크가 꽉 찼다" — 체계적인 진단 절차

# Step 1: 어느 파일시스템이 꽉 찼는지 확인
df -h
# Use%가 90% 이상인 파일시스템을 찾는다

# Step 2: 해당 파일시스템에서 큰 디렉터리 찾기
du -h --max-depth=1 / 2>/dev/null | sort -rh | head -10
# /var가 크다면 → /var 안에서 다시 추적

# Step 3: 범인 디렉터리 좁히기
du -h --max-depth=1 /var/ | sort -rh | head -10
# /var/log가 크다면 → /var/log 안에서 다시 추적

# Step 4: 큰 파일 직접 찾기
find / -type f -size +100M 2>/dev/null | xargs ls -lhS

# Step 5: 삭제되었지만 공간을 차지하는 파일 확인
lsof +L1 2>/dev/null

inode 고갈 문제

디스크 공간은 남아있는데 "No space left on device" 에러가 발생하면 inode 고갈을 의심해야 한다. 작은 파일이 수백만 개 생성된 경우에 발생한다.

# inode 사용량 확인
df -i

# 어느 디렉터리에 파일이 많은지 찾기
find / -xdev -printf '%h\n' 2>/dev/null | sort | uniq -c | sort -rn | head -10
# 각 디렉터리의 파일 수를 세어서 정렬

Chapter 09. 텍스트 검색 & 치환

리눅스에서는 거의 모든 것이 텍스트이다.
설정 파일, 로그, 명령어 출력, /proc 파일시스템 — 전부 텍스트 스트림이다.

텍스트 처리의 3대 도구

도구 역할 핵심 용도
grep 검색 (Search) 패턴이 포함된 줄을 찾는다
sed 치환 (Replace) 텍스트를 변환/치환한다
awk 추출/가공 (Extract) 필드 단위로 데이터를 추출/계산한다

정규표현식 (Regular Expression)

grep, sed, awk 모두 정규표현식(regex)을 사용한다.

메타문자 의미 예시 매치 대상
. 임의의 한 문자 h.t hat, hot, hit
^ 줄의 시작 ^Error Error로 시작하는 줄
$ 줄의 끝 \.log$ .log로 끝나는 줄
* 앞 문자가 0회 이상 ab*c ac, abc, abbc
+ 앞 문자가 1회 이상 (ERE) ab+c abc, abbc (ac는 안됨)
? 앞 문자가 0회 또는 1회 (ERE) colou?r color, colour
[] 문자 클래스 (하나) [aeiou] 모음 한 글자
[^] 부정 문자 클래스 [^0-9] 숫자가 아닌 문자
` ` OR (ERE) `cat
() 그룹핑 (ERE) (ab)+ ab, abab, ababab
\b 단어 경계 \berror\b "error" 단어만 (errors 제외)

BRE vs ERE

  • BRE (Basic Regular Expression): grep, sed의 기본 모드. +, ?, |, () 사용 시 앞에 \를 붙여야 한다.
  • ERE (Extended Regular Expression): grep -E (또는 egrep), sed -E, awk의 기본 모드. \ 없이 바로 사용 가능하다.
# BRE (grep 기본)
grep "error\|fail" logfile        # \| 필요

# ERE (grep -E) — 더 깔끔하다
grep -E "error|fail" logfile      # | 그대로 사용

특별한 이유가 없으면 항상 grep -E를 사용하는 것이 편하다.

자주 쓰는 패턴 모음

# IP 주소 패턴
[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

# 날짜 패턴 (YYYY-MM-DD)
[0-9]{4}-[0-9]{2}-[0-9]{2}

# 이메일 패턴 (간략)
[a-zA-Z0-9.]+@[a-zA-Z0-9.]+

# 빈 줄
^$

# 주석 줄 (# 또는 //)
^#|^//

# 숫자만
^[0-9]+$

grep — 텍스트 검색

정규표현식 검색

# ERE 모드로 여러 패턴 동시 검색
grep -E "error|warning|critical" /var/log/syslog

# IP 주소 추출
grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" /var/log/auth.log

# 특정 날짜의 로그만 추출
grep "^2025-03-23" /var/log/app.log

# 특정 패턴 사이의 줄 (시작 패턴 ~ 끝 패턴)
grep -A 100 "BEGIN CERTIFICATE" cert.pem | grep -B 100 "END CERTIFICATE"

o 옵션 — 매치된 부분만 출력

# 줄 전체가 아닌, 매치된 부분만 출력
grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log

# 로그에서 HTTP 상태 코드만 추출
grep -oE "HTTP/[0-9.]+ [0-9]{3}" access.log

grep 조합 패턴

# 여러 조건을 AND로 결합 (grep 파이프 체인)
grep "2025-03-23" app.log | grep "ERROR" | grep "database"
# → 3월 23일 + ERROR + database 포함하는 줄

# 특정 패턴 제외 (NOT)
grep "error" app.log | grep -v "timeout"
# → error를 포함하지만 timeout은 포함하지 않는 줄

# 전후 맥락과 함께 보기
grep -C 5 "OOM" /var/log/syslog
# → Out Of Memory 전후 5줄씩

sed — 스트림 편집기

Stream Editor의 약자이다.
텍스트를 줄 단위로 읽어서 변환하는 도구이다. 가장 많이 사용하는 기능은 치환이다.

치환

# 기본 치환: 각 줄에서 첫 번째 매치만 변환
sed 's/old/new/' file.txt

# 모든 매치 변환 (g = global) ★★★
sed 's/old/new/g' file.txt

# 대소문자 무시 (i 플래그)
sed 's/error/ERROR/gi' file.txt

# 특정 줄만 치환
sed '3s/old/new/' file.txt        # 3번째 줄만
sed '1,5s/old/new/g' file.txt     # 1~5번째 줄만

원본 파일 직접 수정 (i)

기본적으로 sed는 결과를 stdout으로 출력하며, 원본 파일은 변경하지 않는다. -i 옵션을 사용하면 원본 파일을 직접 수정한다.

# 원본 파일을 직접 수정 ★★★
sed -i 's/old/new/g' config.yaml

# 백업을 만들면서 수정 (안전한 방법)
sed -i.bak 's/old/new/g' config.yaml
# config.yaml → 수정됨
# config.yaml.bak → 원본 백업

# macOS에서는 -i 뒤에 빈 문자열을 반드시 지정해야 한다
sed -i '' 's/old/new/g' config.yaml    # macOS

활용 예시

# 1. 설정 파일의 특정 값 변경
sed -i 's/^port=.*/port=8080/' app.conf
# port= 으로 시작하는 줄의 값을 8080으로 변경

# 2. 여러 파일에서 일괄 치환
find /etc/myapp -name "*.conf" -exec sed -i 's/old-server/new-server/g' {} +

# 3. 파일에서 특정 범위 추출
sed -n '10,20p' file.txt    # 10~20번째 줄만 출력 (-n + p)

# 4. 환경별 설정 파일 생성
sed 's/{{DB_HOST}}/prod-db.example.com/g; s/{{DB_PORT}}/5432/g' template.conf > prod.conf

awk — 필드 기반 텍스트 처리

awk는 텍스트를 필드(열) 단위로 분리하여 처리하는 프로그래밍 언어이다. 이름은 개발자 세 명(Aho, Weinberger, Kernighan)의 이니셜에서 유래했다.

기본 동작 원리

awk는 입력을 줄(record) 단위로 읽고, 각 줄을 필드(field)로 분리한 뒤 처리한다.

입력: "devops  1234  /bin/bash"

$0 = "devops  1234  /bin/bash"    (줄 전체)
$1 = "devops"                     (1번째 필드)
$2 = "1234"                       (2번째 필드)
$3 = "/bin/bash"                  (3번째 필드)
NF = 3                            (필드 수)
NR = (현재 줄 번호)

기본 필드 구분자는 공백/탭이다. -F 옵션으로 변경할 수 있다.

# 특정 필드만 출력
awk '{print $1}' /etc/passwd           # 첫 번째 필드 (구분자: 공백)
awk -F: '{print $1}' /etc/passwd       # 구분자를 :으로 지정 → 사용자명

# 여러 필드 출력
awk -F: '{print $1, $3}' /etc/passwd   # 사용자명, UID
awk -F: '{print $1 ":" $3}' /etc/passwd  # 사용자명:UID (포맷 지정)

조건부 처리

awk는 패턴 { 동작 } 형식으로 조건부 처리를 할 수 있다.

# 특정 조건에 맞는 줄만 처리
awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd
# UID가 1000 이상인 사용자만 출력 (일반 사용자)

# 특정 문자열이 포함된 줄
awk '/error/ {print}' /var/log/syslog
# grep "error"와 동일하지만, awk는 필드 추출까지 가능

# 특정 필드가 조건을 만족하는 줄
awk '$9 == 500 {print $7}' access.log
# HTTP 상태 코드(9번째 필드)가 500인 줄에서 URL(7번째 필드)만 추출

계산과 집계

awk의 가장 강력한 기능은 데이터 집계이다.

# 합계 계산
awk '{sum += $1} END {print sum}' numbers.txt

# 평균 계산
awk '{sum += $1; count++} END {print sum/count}' numbers.txt

# 최대값
awk 'BEGIN {max=0} $1 > max {max=$1} END {print max}' numbers.txt

BEGIN과 END 블록:

  • BEGIN { ... }: 입력을 처리하기 전에 한 번 실행된다 (초기화)
  • END { ... }: 모든 입력을 처리한 후에 한 번 실행된다 (결과 출력)

실무 활용 예시

# 1. Nginx 액세스 로그에서 IP별 요청 수 집계
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# 2. 디스크 사용률이 80% 이상인 파티션 알림
df -h | awk 'NR>1 && +$5 >= 80 {print "WARNING:", $6, "is", $5, "full"}'

# 3. 프로세스별 메모리 사용량 합계
ps aux | awk 'NR>1 {mem[$11] += $6} END {for (p in mem) print mem[p]/1024 "MB", p}' | sort -rn | head -10

# 4. CSV에서 특정 열의 합계
awk -F',' '{sum += $3} END {printf "Total: %.2f\n", sum}' sales.csv

# 5. 로그에서 시간대별 에러 수 집계
grep "ERROR" app.log | awk '{print substr($1,1,13)}' | sort | uniq -c
# 시간(hour) 단위로 에러 발생 빈도 확인

'Learning Log' 카테고리의 다른 글

[멋사 클라우드 5기] Day 37 & 38 - Linux (3)  (0) 2026.03.25
[멋사 클라우드 5기] Day 35 & 36 - Linux (2)  (0) 2026.03.25
[멋사 클라우드 5기] Day 31 & 32 - OSI 7 Layers  (1) 2026.03.16
[멋사 클라우드 5기] Day 29 & 30 - 게시판 구현을 통해 확인한 Spring Data JPA  (0) 2026.03.12
[멋사 클라우드 5기] Day 28 - JWT 그런데 Redis를 곁들인  (0) 2026.03.10
'Learning Log' 카테고리의 다른 글
  • [멋사 클라우드 5기] Day 37 & 38 - Linux (3)
  • [멋사 클라우드 5기] Day 35 & 36 - Linux (2)
  • [멋사 클라우드 5기] Day 31 & 32 - OSI 7 Layers
  • [멋사 클라우드 5기] Day 29 & 30 - 게시판 구현을 통해 확인한 Spring Data JPA
allluck777
allluck777
allluck777
    • 분류 전체보기 (42) N
      • AWS (0)
      • Network (0)
      • Linux (0)
      • Docker (0)
      • Project (4)
        • CloudNote (4)
      • Learning Log (35) N
      • Lecture (3)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (3)
  • 전체
    오늘
    어제
  • hELLO· Designed By정상우.v4.10.6
allluck777
[멋사 클라우드 5기] Day 33 & 34 - Linux (1)
상단으로

티스토리툴바