Featured image of post [Bash Shell] 38. gzip - 압축과 해제

[Bash Shell] 38. gzip - 압축과 해제

리눅스·유닉스에서 gzip으로 단일 파일을 DEFLATE 알고리즘으로 압축·해제하는 방법, -k·-9·-r 옵션과 압축률·속도 트레이드오프, 원본 파일이 사라지는 파괴적 기본 동작의 함정, zstd·xz·tar와의 역할 분담을 다룹니다.

gzip은 리눅스·유닉스에서 단일 파일을 DEFLATE 알고리즘으로 압축하고, gunzip(또는 gzip -d)은 그 압축을 해제하는 명령어다. 로그 회전, 백업 아카이브의 마지막 단계, 네트워크로 파일을 전송하기 전 용량을 줄이는 용도로 리눅스 생태계 전반에서 가장 널리 쓰이는 압축 도구이며, .tar.gz처럼 다른 도구와 조합돼 쓰이는 경우가 실무에서는 더 흔하다.

이 장을 읽기 전에

선행 챕터: 이 장은 37장: find에서 조건에 맞는 파일을 찾아내는 법을 다룬 뒤 이어진다. find로 오래된 로그나 대용량 파일을 골라냈다면, 이 장에서는 그렇게 찾아낸 파일을 실제로 압축해 디스크 공간을 회수하는 법을 다룬다. 별도의 셸 스크립팅 지식은 필요 없고, 파일과 디렉터리·리다이렉션(>) 개념 정도만 있으면 충분하다.

이 장의 깊이: 입문 난이도다. gzip은 옵션 수가 적고 동작이 단순한 도구라, 기본 압축·해제부터 압축 수준 조절, 무결성 검사까지가 실무에서 쓰는 범위 전부다. 다루지 않는 것: gzip은 파일 하나만 압축한다. 여러 파일과 디렉터리 구조를 하나로 묶는 법은 39장: tar에서 다룬다. gzip이 내부적으로 쓰는 DEFLATE 알고리즘의 상세 구현(허프만 코딩, LZ77 슬라이딩 윈도)은 이 글에서 다루지 않는다.

당신의 수준에 맞는 경로

수준읽을 부분핵심 목표
로그·파일 하나를 바로 압축/해제하고 싶은 사람개요+정신 모델, 사용법·옵션, 예시의 “기본 압축·해제”~“재귀 압축”gzip/gunzip으로 파일을 압축·해제하고 원본을 보존하는 법을 안다
압축 전략을 판단해야 하는 사람(백업·전송 최적화)예시의 “압축 수준 비교”~“무결성 검사”, 주의사항·함정 전체압축 수준별 트레이드오프를 이해하고, 상황에 맞게 gzip·zstd·xz 중 선택할 수 있다

개요 + 정신 모델

gzip을 이해하는 가장 중요한 사실 하나는, 이 도구가 아카이버(archiver)가 아니라 압축기(compressor) 라는 점이다. gzip은 입력 스트림 하나를 받아 DEFLATE 알고리즘(LZ77 방식의 반복 문자열 치환 + 허프만 코딩)으로 인코딩한 출력 스트림 하나를 만들어낼 뿐이다. 마치 파이프의 한쪽 끝에 파일을 넣으면 다른 쪽 끝에서 더 작아진 같은 내용이 나오는 변환기에 가깝다 — 그래서 .gz 파일은 항상 원본 파일 하나에 대응하고, 여러 파일이나 디렉터리 트리를 하나의 .gz로 묶을 방법이 애초에 없다.

이 정신 모델은 실무에서 왜 tar czf archive.tar.gz dir/처럼 두 도구를 항상 같이 쓰는지를 설명해 준다. tar가 먼저 여러 파일과 디렉터리 구조를 순서가 있는 하나의 스트림(아카이브)으로 직렬화하면, 그다음 gzip이 그 스트림 전체를 압축한다. gzip 입장에서는 상대가 파일 1개든 tar가 만든 아카이브 스트림이든 구분하지 않는다 — 그저 입력 스트림 하나를 압축할 뿐이다. 이 역할 분담(묶기는 tar, 압축은 gzip)은 다음 장에서 완성된다.

사용법 · 옵션

1
2
gzip [옵션] [파일...]
gunzip [옵션] [파일...]
  • 파일: 압축(또는 해제)할 대상. 생략하면 표준 입력에서 읽고 표준 출력으로 쓴다.
  • gunzipgzip -d와 동일하게 동작하는 별도 이름(alias)이다. zcatgunzip -c와 같아서, 압축 파일을 해제된 상태로 표준 출력에 바로 뿌려준다(원본도 .gz도 건드리지 않는다).

압축·해제 제어

옵션설명
-d, --decompress압축 해제 (gunzip과 동일)
-k, --keep원본 파일을 지우지 않고 유지
-c, --stdout결과를 표준 출력으로 보내고 원본은 건드리지 않는다
-f, --force대상 파일이 이미 있거나 심볼릭 링크여도 강제로 압축·해제
-r, --recursive디렉터리를 지정하면 하위 파일까지 재귀적으로 압축

압축 수준

옵션설명
-1, --fast최소 압축, 최고 속도
-6기본값(속도·압축률 절충)
-9, --best최대 압축, 최저 속도

정보·검증

옵션설명
-l, --list압축 파일의 압축 전/후 크기, 압축률, 원본 파일명을 출력
-t, --test압축 파일을 해제하지 않고 무결성만 검사
-v, --verbose파일별 압축률을 처리 중에 함께 출력
-N, --name해제 시 압축 파일에 저장된 원래 파일명·타임스탬프를 복원(전송 중 이름이 잘렸을 때 유용)

예시

기본 압축·해제

1
2
3
gzip access.log        # access.log.gz 생성, access.log는 사라진다
gunzip access.log.gz    # access.log 복원, access.log.gz는 사라진다
gzip -d access.log.gz   # gunzip과 동일한 결과

원본을 남기고 압축

1
2
3
4
5
# access.log는 그대로 두고 access.log.gz만 추가로 생성
gzip -k access.log

# 표준 출력으로 보내 원본과 무관하게 압축 파일을 별도 경로에 생성
gzip -c access.log > /backup/access.log.gz

디렉터리 재귀 압축

1
2
# logs/ 아래 모든 파일을 각각 개별 .gz로 압축 (디렉터리 구조는 그대로, 파일마다 압축)
gzip -r logs/

압축 수준 비교

1
2
3
4
# 기본(-6)과 최대 압축(-9)의 크기·시간 차이 확인
time gzip -k -6 -c bigfile.log > bigfile.default.gz
time gzip -k -9 -c bigfile.log > bigfile.best.gz
ls -lh bigfile.default.gz bigfile.best.gz

압축률 확인과 무결성 검사

1
2
3
4
5
# 압축 전/후 크기와 압축률을 표로 확인
gzip -l access.log.gz

# 손상 여부만 확인 (해제하지 않음)
gzip -t access.log.gz && echo "정상"

압축 파일 내용을 풀지 않고 확인

1
2
3
4
5
# 압축 해제 없이 내용만 표준 출력으로 확인
zcat access.log.gz

# grep과 조합해 압축 로그에서 바로 검색 (해제된 파일을 디스크에 남기지 않는다)
zcat access.log.gz | grep "500 Internal"

tar와 조합 (39장에서 완성)

1
2
# tar가 여러 파일을 스트림으로 묶고, gzip이 그 스트림을 압축
tar cf - project/ | gzip -9 > project.tar.gz

주의사항·함정

gzip은 기본적으로 원본 파일을 압축 파일로 대체한다. gzip file.txt를 실행하면 file.txt.gz가 생기는 동시에 file.txt 자체는 삭제된다 — 별도 확인 없이 즉시 일어나는 동작이라, 원본을 계속 참조하는 스크립트나 다른 프로세스가 있다면 그 순간 대상을 잃는다. 원본을 유지하려면 항상 -k(--keep)를 명시하거나, -c로 표준 출력에 결과를 받아 별도 파일로 리다이렉션해야 한다. 압축 해제(gunzip)도 동일한 원칙으로 동작해 .gz 파일이 사라지므로, 마찬가지로 -k가 필요하면 명시한다.

-9가 항상 정답은 아니다. 압축 수준은 속도와 압축률 사이의 트레이드오프이지, 무조건 -9를 쓴다고 실무에 유리해지는 것이 아니다. 텍스트(소스 코드·로그)는 기본값(-6)만으로도 원본 대비 60–70%가량 줄어드는 경우가 많고, -9로 올려도 얻는 추가 절감폭은 크지 않은 반면 압축에 걸리는 CPU 시간은 눈에 띄게 늘어난다. 이미 압축된 형식(JPEG, MP4, 이미 .gz인 파일 등)은 데이터에 반복 패턴이 거의 남아있지 않아 -9를 써도 크기가 거의 줄지 않거나 오히려 gzip 헤더만큼 늘어날 수 있다. 대용량 파일을 반복 압축하는 배치 작업이라면 -1~-6 구간에서 실제 속도·크기를 측정해 보고 결정하는 편이 안전하다.

.gz는 단일 스트림이라 디렉터리 구조를 담지 못한다. gzip -r dir/은 디렉터리를 순회하며 그 안의 파일들을 각각 개별 .gz로 압축할 뿐, 디렉터리 트리 자체를 하나의 아카이브로 묶어주지 않는다. 여러 파일과 디렉터리 계층 구조(권한·소유자·심볼릭 링크 포함)를 통째로 하나의 산출물로 만들고 싶다면 tar로 먼저 묶은 뒤 gzip으로 압축해야 한다 — 이 역할 분담은 이 장의 정신 모델에서 이미 짚었고, 39장: tar에서 실제 명령으로 완성한다.

최근에는 zstd·xz가 대안으로 자주 쓰인다. gzip이 쓰는 DEFLATE는 1990년대에 설계된 알고리즘이라, 이후 나온 xz(LZMA2 기반)는 같은 압축 수준에서 gzip보다 압축률이 눈에 띄게 높지만 압축 속도는 더 느리고 메모리도 더 쓴다. zstd는 반대로 압축·해제 속도가 매우 빠르면서도(초당 수백 MB급) 압축률은 상황에 따라 gzip과 비슷하거나 나은 수준을 낸다. 실무 기준으로는 압축·해제 속도가 중요한 실시간 파이프라인·백업에는 zstd, 배포 아카이브처럼 크기를 최대한 줄여야 하는 경우엔 xz, 그리고 어느 시스템에나 기본 설치돼 있어 호환성이 최우선인 상황(레거시 스크립트, 오래된 서버)에는 여전히 gzip을 선택하는 식으로 나뉜다.

흔한 오개념

"gzip으로 여러 파일이나 폴더 전체를 압축할 수 있다"는 정확하지 않다. gzip file1.txt file2.txt를 실행하면 file1.txt.gzfile2.txt.gz라는 개별 압축 파일 두 개가 만들어질 뿐, 두 파일을 하나로 묶은 산출물은 생기지 않는다. 여러 파일을 하나의 결과물로 묶으려면 반드시 tar 같은 아카이버를 먼저 거쳐야 한다.

".gz는 .zip과 같은 것"이라는 오해도 흔하다. Windows에서 익숙한 .zip은 압축과 아카이빙(여러 파일 묶기)을 하나의 포맷 안에서 동시에 처리하지만, 유닉스 계열 전통에서는 “묶기”(tar)와 “압축”(gzip)을 서로 다른 도구의 책임으로 분리해 왔다. 이 설계는 각 도구를 다른 목적으로도 재사용할 수 있게 한다는 장점이 있다 — 예컨대 tar로 묶은 스트림을 gzip 대신 xzzstd로 압축하는 것도 같은 원리로 가능하다.

다음 장에서는

gzip은 파일 하나만 압축한다. 여러 파일/디렉터리를 하나로 묶는 법은 다음 장에서 다룬다 — 39장: tar에서 tar로 디렉터리 구조를 하나의 아카이브로 묶고, 그 아카이브를 다시 gzip으로 압축해 .tar.gz를 완성하는 전체 과정을 실습한다.

평가 기준

  • gzip이 아카이버가 아니라 압축기라는 정신 모델을 설명하고, tar와 역할이 어떻게 나뉘는지 말할 수 있다.
  • -k, -c, -r, 압축 수준(-1~-9) 옵션을 조합해 원본을 보존하며 원하는 파일을 압축·해제할 수 있다.
  • 원본 파일이 기본적으로 삭제된다는 점과, 이를 회피하는 방법을 설명할 수 있다.
  • 압축 수준을 무조건 최대로 높이지 않아야 하는 이유(속도·CPU 대비 절감폭 감소)를 설명할 수 있다.
  • 상황에 따라 gzip·zstd·xz 중 무엇을 선택할지 압축률·속도·호환성 기준으로 판단할 수 있다.

참고