Devin.KR
로그인

리눅스 diff 명령어 사용법 - 서버 설정 파일 비교와 unified diff 읽는 법

개발자 조회 1

이 명령어를 언제 쓰는가

git 이 모든 코드를 관리하는 시대에도 서버에서 diff 를 쓰는 이유는 분명하다. /etc 아래 설정 파일은 대부분 git 밖에 있기 때문이다. "어제까지 잘 되던 nginx 가 왜 안 뜨는가"를 볼 때 백업본과 현재 파일을 비교하는 것이 가장 빠른 길이다.

패키지 업그레이드가 남긴 .dpkg-dist·.rpmnew 파일과 실제 설정을 대조하는 일, 두 서버가 정말 같은 설정으로 돌고 있는지 확인하는 일도 전부 diff 다. 그리고 diff 의 출력은 그대로 patch 의 입력이 된다 — 이 두 명령은 한 세트로 익혀야 한다.

기본 형식

diff [옵션] 원본 변경본

인자 순서가 의미를 결정한다. 앞이 이전, 뒤가 이후다. 출력은 "앞을 뒤로 만들려면 무엇을 해야 하는가"를 기술한다. 이 순서를 반대로 두면 추가와 삭제가 뒤집힌 채로 읽히고, 그 diff 로 만든 패치는 반대로 적용된다.

실무에서는 사실상 diff -u 하나만 쓴다. git 이 쓰는 형식이라 눈에 익고, patch 로 적용하기도 쉽다.

자주 쓰는 옵션

옵션의미예시
-uunified 형식. 앞뒤 3줄 문맥을 함께 보여 준다diff -u a.conf b.conf
-r디렉터리를 재귀적으로 비교한다diff -ru /etc/nginx /backup/nginx
-q다른지 여부만 알려 준다. 내용은 출력하지 않는다diff -rq dir1 dir2
-N한쪽에만 있는 파일을 빈 파일로 취급한다. -r과 함께 필수diff -ruN old new
-w모든 공백 차이를 무시한다diff -uw a.conf b.conf
-B빈 줄만 다른 것은 무시한다diff -uB a.conf b.conf
-i대소문자를 무시한다diff -ui a.txt b.txt
-y좌우 두 열로 나란히 보여 준다diff -y a.conf b.conf
--color=always색을 입힌다 (GNU diffutils 3.4 이상)diff --color=always -u a b | less -R

실전 예제

1) 백업본과 현재 설정을 비교한다. 장애 원인이 설정 변경인지 5초 만에 판별한다.

diff -u /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
--- /etc/nginx/nginx.conf.bak	2026-08-25 22:20:11
+++ /etc/nginx/nginx.conf	2026-08-25 22:31:04
@@ -1,4 +1,5 @@
 server {
-  listen 80;
+  listen 443 ssl;
   root /var/www;
+  gzip on;
 }

읽는 법은 간단하다. @@ -1,4 +1,5 @@ 는 "원본의 1번째 줄부터 4줄이 변경본의 1번째 줄부터 5줄로 바뀐다"는 뜻이다. - 는 원본에서 빠지는 줄, + 는 새로 들어가는 줄, 앞이 공백인 줄은 문맥이다.

2) 두 서버의 설정 디렉터리 전체를 대조한다. "web01 은 되는데 web02 는 안 된다"의 원인을 찾는 상황이다.

rsync -a web02:/etc/nginx/ /tmp/nginx-web02/
diff -ruN /etc/nginx/ /tmp/nginx-web02/

3) 어떤 파일이 다른지 목록만 먼저 본다. 파일이 수백 개일 때 내용까지 다 뽑으면 읽을 수가 없다.

diff -rq /etc/nginx/ /tmp/nginx-web02/
Only in /etc/nginx/conf.d: legacy.conf
Files /etc/nginx/nginx.conf and /tmp/nginx-web02/nginx.conf differ

4) 들여쓰기만 바뀐 잡음을 걷어 낸다. 편집기가 탭을 공백으로 바꿔 버려 전부 다르게 나올 때 쓴다.

diff -uw /etc/php/8.2/fpm/php.ini /etc/php/8.2/fpm/php.ini.dpkg-dist

5) 파일이 아니라 명령의 출력을 비교한다. 프로세스 치환을 쓰면 임시 파일이 필요 없다.

diff -u <(ssh web01 'systemctl list-unit-files --state=enabled') \
        <(ssh web02 'systemctl list-unit-files --state=enabled')

6) 변경 사항을 패치 파일로 남긴다. 다른 서버에 같은 수정을 적용하려는 상황이다.

diff -u nginx.conf.orig nginx.conf > nginx-ssl.patch

함정과 주의점

diff 의 종료 코드는 0이 "같음"이다. 스크립트에서 흔히 뒤집어 쓴다. 0은 동일, 1은 차이 있음, 2 이상은 에러다. 즉 diff a b || echo "에러" 는 파일이 다를 때도 에러라고 찍는다.

if diff -q /etc/app.conf /backup/app.conf > /dev/null; then
  echo "동일"
else
  echo "변경됨"
fi

set -e 가 걸린 스크립트에서 diff 를 그냥 쓰면 파일이 다르다는 이유만으로 스크립트가 죽는다. diff a b || true 로 감싸거나 종료 코드를 명시적으로 받아야 한다.

보이지 않는 차이가 diff 를 지저분하게 만든다. 윈도우에서 편집한 파일의 CR(\r), 줄 끝 공백, 파일 마지막의 개행 유무가 대표적이다. 마지막 줄이 개행 없이 끝나면 diff 가 \ No newline at end of file 을 붙인다. 눈으로 같아 보이는데 diff 가 다르다고 하면 cat -A(GNU) 또는 cat -et(BSD)로 실제 바이트를 확인한다.

-r 만 쓰고 -N 을 빠뜨리면 신규 파일이 내용 없이 지나간다. 한쪽에만 있는 파일은 Only in ... 한 줄로만 표시되고 diff 본문에 안 들어간다. 그 diff 로 패치를 만들면 새 파일이 통째로 누락된다. 디렉터리 비교는 diff -ruN 을 습관으로 쓴다.

바이너리 파일에는 쓰지 않는다. Binary files a and b differ 한 줄만 나온다. 바이너리는 cmp 나 체크섬(sha256sum) 비교가 맞다.

타임스탬프 형식이 GNU 와 BSD 에서 다르다. GNU 는 나노초와 타임존까지 붙이고 BSD 는 초 단위까지만 쓴다. 패치 적용에는 지장이 없지만, diff 출력을 문자열로 비교하는 스크립트라면 걸린다.

함께 보면 좋은 명령어

  • patch — diff 가 만든 결과를 실제 파일에 적용한다. 정확히 짝이 되는 명령이다.
  • comm — 파일 내용이 아니라 정렬된 목록의 집합 연산이 목적이면 이쪽이 간결하다.
  • cmp — 바이너리가 몇 번째 바이트부터 다른지 알고 싶을 때 쓴다.