개발 환경·도구

vi 편집기, 딱 이 10개 명령만 알면 서버에서 안 막힙니다

vi 편집기, 딱 이 10개 명령만 알면 서버에서 안 막힙니다

SSH로 서버에 접속해서 설정 파일 한 줄만 고치려고 했는데, 갑자기 까만 화면이 뜨고 왼쪽에 물결표(~)만 잔뜩 늘어선 화면을 만난 적이 있을 겁니다. 글자를 쳐도 안 써지고, Ctrl+C를 눌러도 안 나가고, 창을 닫자니 뭔가 잘못될 것 같고. 그게 vi입니다. 리눅스 서버를 조금이라도 만지면 언젠가는 반드시 마주치는 편집기죠.

vi가 악명 높은 건 명령어가 많아서가 아닙니다. 처음 보는 사람 기준으로 “글자를 입력하려면 먼저 입력하겠다고 선언해야 한다”는 발상 자체가 낯설어서 그렇습니다. 이 구조 하나만 이해하면 나머지는 명령 열 개 남짓으로 끝납니다. vim을 능숙하게 다루는 게 목표가 아니라, 파일 열고 한 줄 고치고 저장하고 빠져나오는 것만 확실하게 만드는 게 목표입니다.

한눈에 · 모드 3종 이해(ESC의 역할) → vi 파일명으로 열고 i로 수정 → ESC 후 :wq 저장 종료 → 검색·치환·줄이동 몇 개 추가 → readonly·swap 경고 대처까지

왜 서버에서는 결국 vi를 만나게 되나

“난 nano가 편한데”라고 생각할 수 있습니다. 문제는 서버에 nano가 없는 경우가 꽤 많다는 겁니다. 최소 설치(minimal) 이미지로 올린 CentOS나 Ubuntu, 그리고 도커 컨테이너 안에 들어가면 편집기라고는 vi 하나만 있는 상황이 흔합니다. 패키지를 설치하면 되긴 하지만, 급한 상황에 인터넷도 안 되는 내부망 서버라면 그마저 어렵습니다.

게다가 내가 선택하지 않아도 vi가 강제로 열리는 자리가 있습니다. 대표적인 게 이런 것들입니다.

상황열리는 것
sudo visudosudoers 편집, 기본 에디터가 vi인 배포판 다수
crontab -e스케줄 편집, EDITOR 환경변수 없으면 vi
git commit (메시지 없이)커밋 메시지 편집기
systemctl edit 서비스명유닛 오버라이드 파일

crontab을 편집하다 vi에서 못 빠져나온 경험이 있다면 crontab 작성법 정리, 등록해도 안 돌아가는 이유까지도 같이 보면 도움이 됩니다. 저장이 안 되면 크론도 등록이 안 되니까요.

참고로 vi와 vim은 이름이 다릅니다. 대부분의 리눅스 배포판에서 vi를 치면 실제로는 vim(또는 vim의 축소판인 vim-minimal)이 실행됩니다. 확인은 이렇게 합니다.

vi --version | head -1

VIM - Vi IMproved로 시작하는 줄이 나오면 vim입니다. 이 글의 명령은 둘 다에서 동작합니다.

vi가 어려운 진짜 이유는 명령 개수가 아니라 ‘모드’

목표를 좁혔으니, 이제 왜 키를 눌러도 글자가 안 써지는지부터 풀어야 합니다. vi에는 모드라는 게 있습니다. 같은 키를 눌러도 지금 어느 모드냐에 따라 완전히 다르게 동작합니다. 메모장에서 d를 누르면 d가 써지지만, vi의 일반 모드에서 dd를 누르면 줄이 통째로 지워집니다.

기억할 모드는 세 개면 충분합니다.

모드하는 일들어가는 법
일반 모드 (Normal)이동, 삭제, 복사 등 ‘명령’을 내리는 상태. vi를 열면 여기서 시작ESC
입력 모드 (Insert)글자가 그대로 써지는 상태. 우리가 아는 메모장일반 모드에서 i
명령행 모드 (Command-line)화면 맨 아래에 :가 뜨고 저장·종료 명령을 치는 상태일반 모드에서 :

지금 내가 어느 모드인지는 화면 맨 아래를 보면 됩니다. 입력 모드면 -- INSERT --라고 표시됩니다. 아무것도 없으면 일반 모드입니다. 모르겠으면 무조건 ESC를 누르세요. ESC는 어디서든 일반 모드로 되돌아가는 키입니다.

모드 전환 흐름도: ESC ↔ i ↔ :

흐름은 단순합니다. 일반 모드가 중심이고, 거기서 i로 입력 모드에 들어갔다가 ESC로 돌아오고, :로 명령행에 들어갔다가 명령을 실행하면 다시 돌아옵니다. 입력 모드에서 곧바로 :wq를 칠 수는 없습니다. 그러면 그냥 화면에 :wq라는 글자가 써집니다.

vi 모드 전환의 기본 흐름
vi 모드 전환의 기본 흐름

헷갈리면 ESC를 두 번 누르고 시작한다

실전 팁 하나. 뭔가 이상하게 동작하면 ESC를 두 번 누르고 다시 시작하세요. 한 번으로 충분하지만 두 번 눌러도 아무 부작용이 없습니다. 이미 일반 모드일 때 ESC를 누르면 터미널에서 짧게 삑 소리가 나거나 화면이 한 번 깜빡일 뿐입니다.

실제로 파일 하나 고쳐보기: 열기부터 저장까지

모드를 머리로 이해했으면 이제 손으로 한 번 해봐야 남습니다. 중요한 설정 파일로 연습하면 곤란하니 아무 데나 연습용 파일을 하나 만들어서 진행하겠습니다.

cd ~
vi test.txt

없는 파일 이름을 주면 vi가 빈 파일을 새로 만들어 엽니다. 화면 왼쪽에 ~가 세로로 쭉 늘어서 있을 텐데, 이건 “여기는 파일 내용이 없는 빈 줄”이라는 표시일 뿐입니다. 오류가 아닙니다. 맨 아랫줄에는 파일 이름과 [New File] 같은 상태 표시가 나옵니다.

첫 사이클: i → 수정 → ESC → :wq

이제 순서대로 해봅니다.

  1. i를 누릅니다. 화면 맨 아래에 -- INSERT --가 뜹니다.
  2. 아무 문장이나 칩니다. hello vi 정도면 됩니다. 방향키로 이동도 됩니다.
  3. ESC를 누릅니다. 아래쪽 -- INSERT --가 사라집니다.
  4. :wq를 치고 Enter. 화면이 원래 셸 프롬프트로 돌아옵니다.

:wq는 write(저장) + quit(종료)입니다. 잘 됐는지는 셸에서 바로 확인할 수 있습니다.

cat test.txt

방금 친 내용이 그대로 나오면 성공입니다. 이 한 사이클이 vi 사용의 90%입니다.

연습용 파일로 한 사이클 돌려보기
연습용 파일로 한 사이클 돌려보기

저장 없이 탈출: :q!

문제는 실수했을 때입니다. 설정 파일을 열었다가 뭘 건드렸는지 모르겠고, 그냥 없던 일로 하고 싶을 때가 있습니다. 그럴 땐 ESC를 누르고 :q!를 칩니다. 느낌표는 “변경 사항 무시하고 강제로”라는 뜻입니다.

:q만 치면 이런 메시지가 나오면서 안 나가집니다.

E37: No write since last change (add ! to override)

“저장 안 한 변경이 있다, 강제로 나가려면 !를 붙여라”는 안내입니다. 겁먹지 말고 :q!를 치면 됩니다.

이 정도만 외울 최소 목록 표

일단 아래 표만 손에 붙으면 서버 작업은 거의 다 됩니다.

명령모드하는 일
i일반 → 입력커서 위치부터 입력 시작
ESC어디서나일반 모드로 복귀
:w일반 → 명령행저장만 하고 계속 편집
:q일반 → 명령행종료 (변경 있으면 거부)
:q!일반 → 명령행저장 안 하고 강제 종료
:wq일반 → 명령행저장하고 종료
dd일반커서가 있는 줄 삭제
u일반방금 한 작업 되돌리기
gg일반파일 맨 위로
G일반파일 맨 아래로
/검색어일반아래 방향으로 검색
:%s/a/b/g일반 → 명령행파일 전체에서 a를 b로 치환

설정 파일 편집에 실제로 쓰는 명령 몇 개 더

저장과 종료가 손에 붙었다면, 실무에서 반복되는 동작이 몇 개 더 있습니다. 나열식으로 외우려 하지 말고 “이럴 때 이걸 쓴다”로 묶어서 보는 게 낫습니다.

줄 단위 작업이 먼저입니다. dd는 커서가 있는 줄을 통째로 지웁니다. 주석 처리된 설정 줄을 지울 때 자주 씁니다. yy는 그 줄을 복사, p는 커서 아래에 붙여넣기입니다. 비슷한 설정 줄을 하나 더 만들 때 yy → p → 값만 수정하는 식으로 씁니다. 뭔가 잘못했으면 u를 누르면 됩니다. 여러 번 눌러 계속 되돌릴 수 있습니다.

이동은 gg(맨 위), G(맨 아래), 그리고 :숫자입니다. 예를 들어 nginx 설정을 고치다가 이런 에러를 봤다고 해보죠.

nginx: [emerg] unknown directive "serevr_name" in /etc/nginx/nginx.conf:87

87번 줄이 문제라는 뜻입니다. vi로 파일을 열고 :87을 치면 그 줄로 바로 갑니다. 87G도 같은 동작입니다.

줄 번호와 :set paste — 설정 파일 붙여넣을 때 필수

에러가 알려준 줄 번호를 찾으려면 화면에 줄 번호가 보여야 편합니다.

:set number

끄고 싶으면 :set nonumber입니다. 이 설정은 지금 연 파일에만 적용되고, 나가면 사라집니다.

그리고 초보자가 가장 많이 당하는 함정이 붙여넣기입니다. 블로그나 문서에서 설정 블록을 복사해서 입력 모드에서 Ctrl+V(또는 터미널 우클릭)로 붙이면, 이렇게 계단처럼 들여쓰기가 점점 밀리는 현상이 생깁니다.

server {
    listen 80;
        server_name example.com;
            root /var/www/html;

vi가 자동 들여쓰기를 켠 상태라 한 줄 붙일 때마다 앞 줄 들여쓰기를 또 더하기 때문입니다. 붙여넣기 전에 일반 모드에서 :set paste를 치면 자동 들여쓰기가 꺼져서 원본 그대로 들어갑니다. 붙여넣기가 끝나면 :set nopaste로 되돌립니다.

검색 /와 치환 :%s 실사용 예시

긴 설정 파일에서 특정 항목을 찾을 때는 검색이 빠릅니다. 일반 모드에서 /를 누르면 화면 아래에 /가 뜹니다. 거기에 찾을 단어를 치고 Enter.

/PermitRootLogin

다음 결과로 넘어가려면 n, 이전 결과로 돌아가려면 N(Shift+n)입니다. 검색어 강조가 계속 남아 거슬리면 :noh로 끕니다.

치환은 :%s/바꿀것/새것/g 형태입니다. %는 파일 전체, g는 한 줄에 여러 번 나와도 전부라는 뜻입니다.

:%s/example.com/mydomain.com/g

한 번에 다 바꾸기가 무서우면 뒤에 c를 더 붙이세요. 하나씩 물어봅니다.

:%s/example.com/mydomain.com/gc

replace with mydomain.com (y/n/a/q/l/^E/^Y)?라고 물어보면 y는 바꾸기, n은 건너뛰기, a는 남은 것 전부, q는 중단입니다. 실수했으면 역시 u로 되돌립니다.

자주 막히는 지점: 저장이 안 되거나 swap 파일 경고가 뜰 때

명령을 다 알아도 여기서 막히는 경우가 있습니다. 원인은 대체로 두 가지입니다. 하나는 권한, 다른 하나는 지난번에 비정상 종료한 흔적입니다.

readonly 경고와 sudo tee 우회

/etc/nginx/nginx.conf 같은 시스템 파일을 그냥 vi로 열면, 열리긴 열리고 수정도 되는 것처럼 보입니다. 그런데 :wq를 치는 순간 이런 메시지가 뜹니다.

E45: 'readonly' option is set (add ! to override)

읽기 전용으로 열렸다는 뜻입니다. 안내대로 :w!를 쳐보면 이번엔 이런 게 나옵니다.

E212: Can't open file for writing

파일 자체에 쓰기 권한이 없는 겁니다. 정석은 처음부터 sudo로 여는 것입니다.

sudo vi /etc/nginx/nginx.conf

문제는 이미 30분 동안 열심히 고쳐놨을 때죠. 나갔다 다시 열면 작업이 날아갑니다. 이럴 때 쓰는 우회 명령이 있습니다.

:w !sudo tee % > /dev/null

%는 지금 열려 있는 파일 이름을 뜻합니다. 편집 중인 내용을 sudo tee에게 넘겨서 대신 쓰게 하는 방식입니다. sudo 비밀번호를 물어볼 수 있습니다. 실행하면 W12: Warning: File "..." has changed and the buffer was changed in Vim as well이라며 다시 읽을지 물어보는데, L(Load File)을 누르면 됩니다. 그 뒤 :q!로 나갑니다.

파일 권한 자체가 헷갈린다면 chmod 755와 644의 실제 차이, 왜 폴더는 755여야 하나를 먼저 정리하고 오는 편이 낫습니다. 권한을 이해하면 언제 sudo가 필요한지 감이 잡힙니다.

swap 파일 경고 대처 순서

파일을 열자마자 이런 노란 경고 화면이 뜨는 경우도 있습니다.

E325: ATTENTION
Found a swap file by the name ".nginx.conf.swp"
          owned by: root   dated: Mon Sep  8 14:22:10 2025
         file name: /etc/nginx/nginx.conf
          modified: YES
         user name: root   host name: web01
        process ID: 3412
While opening file "/etc/nginx/nginx.conf"

(1) Another program may be editing the same file.
(2) An edit session for this file crashed.

Swap file ".nginx.conf.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:

vi는 편집 중에 임시 파일(.파일명.swp)을 만들어 둡니다. 정상 종료하면 지워지지만, SSH 연결이 끊기거나 터미널을 강제로 닫으면 남습니다. 그 흔적을 발견하고 물어보는 겁니다.

선택지는 이렇게 판단합니다.

키의미언제
RRecover, 저장 안 된 내용 복구지난번 작업 내용을 살리고 싶을 때
OOpen Read-Only, 읽기 전용으로 열기내용만 확인할 때
EEdit anyway, 무시하고 편집다른 사람이 동시 편집 중이 아님이 확실할 때
DDelete it, swap 파일 삭제살릴 내용 없이 깨끗하게 시작할 때
QQuit, 그냥 나가기판단이 안 설 때

가장 안전한 순서는 이렇습니다. 먼저 Q로 나온 뒤, 정말 다른 사람이 편집 중인지 확인합니다.

ls -la /etc/nginx/.nginx.conf.swp
ps aux | grep vi

프로세스가 안 살아 있으면 지난번 비정상 종료 흔적입니다. 그러면 D로 지우거나 셸에서 직접 삭제합니다.

sudo rm /etc/nginx/.nginx.conf.swp

프로세스 확인이 익숙하지 않다면 ps와 top으로 프로세스 확인하고 안전하게 종료하는 순서를 참고하세요.

vi에서 완전히 못 나올 때 최후 수단

간혹 vi가 아니라 터미널이 멈춘 경우도 있습니다. 실수로 Ctrl+S를 누르면 터미널 출력이 정지합니다. 키를 눌러도 아무 반응이 없어서 vi가 죽은 줄 알기 쉬운데, 이건 그냥 화면이 잠긴 겁니다. Ctrl+Q를 누르면 풀립니다.

Ctrl+Z를 눌러서 프롬프트로 돌아왔다면 vi가 종료된 게 아니라 백그라운드로 잠시 멈춰(suspend) 있는 상태입니다. 이 상태로 같은 파일을 다시 열면 아까 그 swap 파일 경고가 뜹니다. 돌아가는 방법은 이렇습니다.

jobs
[1]+  Stopped                 vi /etc/nginx/nginx.conf

이렇게 나오면 fg를 치면 원래 vi 화면으로 복귀합니다. 여러 개면 fg %1처럼 번호를 지정합니다. 정말 버릴 작업이라면 kill %1로 정리하고, 남은 swap 파일을 지우면 됩니다.

여기서 더 갈 사람, 그냥 여기서 멈출 사람

여기까지 익혔으면 서버 설정 파일 편집은 대체로 끝납니다. 열고, 찾고, 고치고, 저장하고, 막히면 빠져나오는 것까지 다 됩니다. vim의 매크로나 분할 화면 같은 건 서버 운영에는 사실 거의 안 씁니다. 다만 자주 쓰다 보면 조금 더 편하게 만들고 싶어지긴 합니다.

최소한의 ~/.vimrc

홈 디렉터리에 .vimrc 파일을 만들면 vi를 열 때마다 자동으로 적용됩니다.

vi ~/.vimrc

여기에 이 정도만 넣어도 체감이 달라집니다.

set number          " 줄 번호 표시
set expandtab       " 탭을 공백으로
set tabstop=4       " 탭 폭 4칸
set shiftwidth=4
syntax on           " 문법 색상
set hlsearch        " 검색어 강조
set ignorecase      " 검색 시 대소문자 무시

주의할 점 하나. 이건 내 계정에만 적용됩니다. sudo vi로 열면 root 계정 설정을 따르므로 줄 번호가 안 보일 수 있습니다. root용으로도 필요하면 sudo vi /root/.vimrc에 같은 내용을 넣으세요.

기본 에디터를 nano로 바꾸기

솔직히 vi가 안 맞을 수도 있습니다. crontab -e나 git commit 때 열리는 편집기를 nano로 바꿀 수 있습니다.

export EDITOR=nano

지금 세션에만 적용됩니다. 계속 쓰려면 셸 설정 파일에 넣습니다.

echo 'export EDITOR=nano' >> ~/.bashrc
source ~/.bashrc

물론 nano가 설치돼 있어야 합니다(sudo apt install nano 또는 sudo yum install nano). 그리고 nano가 없는 서버에 긴급하게 들어갈 일은 언제든 생기니, vi 최소 명령은 그래도 알아두는 편이 안전합니다.

제대로 배워보고 싶다면 터미널에 vimtutor를 쳐보세요. vim과 함께 설치되는 대화형 튜토리얼이고, 30분이면 한 바퀴 돕니다. 읽는 게 아니라 직접 키를 눌러가며 진행하는 방식이라 손에 남습니다.

vimtutor

다음에 할 일 체크리스트

  • [ ] vi --version | head -1로 지금 서버의 vi가 vim인지 확인해 둔다
  • [ ] 홈 디렉터리에 test.txt를 만들어 i → 수정 → ESC → :wq 사이클을 세 번 반복한다
  • [ ] 같은 파일에서 :q!로 저장 없이 빠져나오는 것도 해본다
  • [ ] dd, u, gg, G, :87 이동을 연습 파일에서 눌러본다
  • [ ] /검색어와 n, :%s/a/b/gc 치환을 실제로 실행해 본다
  • [ ] 블로그에서 코드 블록을 복사해 :set paste 켜고/끄고 각각 붙여넣어 차이를 눈으로 확인한다
  • [ ] sudo 없이 /etc/hosts를 열고 저장을 시도해 E45: 'readonly' option is set 메시지를 직접 만나본다
  • [ ] 그 상태에서 :w !sudo tee % > /dev/null이 동작하는지 확인한다
  • [ ] vi를 연 채로 Ctrl+Z를 누르고 jobs, fg로 복귀하는 흐름을 익힌다
  • [ ] 필요하면 ~/.vimrc에 set number, syntax on을 넣어둔다
  • [ ] 시간이 나면 vimtutor를 한 바퀴 돌린다

댓글 1개

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다