14 Vim 심화 - Macro (매크로)

드디어 Vim 의 궁극기 Macro 를 살펴볼 차례다.

Vim 매크로

Macro 는 Vim 명령어'들'을 기록하고, 이를 반복할 수 있는 기능이다.

이전에 Vim Micro Macro(dot command)를 활용해서 이전 명령을 바로 반복할 수 있었다. 그러나, 이는 이전 명령을 반복할 뿐, '이동 후 명령' 과 같은 작업에 대해서는 그 반복이 불가능하다.

매크로가 필요한 순간

가령 다음 스크린샷의 좌측과 같은 코드가 있다고 가정해보자. 이를 오른쪽 코드와 같이 바꾸고자 한다. javascript 에서 key 를 그대로 value 에 넣은 뒤 이를 대문자로 바꾸려고 한다. 

Vim Macro 기능을 활용해 좌측 코드를 우측 코드와 같이 바꿔보고자 한다.

일단, jazz 가 포함된 라인(2번줄)에서 vim 을 활용하여 이 과정을 진행해보자.

다음과 같이 기존 코드를 변경할 것이다.

// from
jazz: ""

// to
jazz: "JAZZ"

이를 수행하기 위한 시퀀스는 다음과 같다.

  1. jazz 의 j 로 커서를 이동한다. (^)
  2. 단어를 복사한다. (yiw)
  3. 첫 번째 따옴표로 이동한다. (f")
  4. 복사한 단어를 붙여넣는다. (p)
  5. 붙여넣어진 단어를 대문자로 변경한다. (gUaw)
    *참고: gU{모션} 은 모션 범위를 대문자로 변경한다. gu 는 소문자로.
  6. 아래 줄로 이동한다. (j)

key 에 해당하는 문자열을 value string 에 그대로 넣은 뒤 대문자로 변경하는 예제

위에서 설명한 1~6 과정이 그대로 반복된다면 opera 가 포함된 라인에도 동일한 동작이 수행되게 할 수 있다.

차라리 노가다를 택할 수도 있고, 굳이 매크로를 쓰지 않아도 적절히 몇번 반복하면 끝난다고 생각할 수도 있겠지만, 동일한 작업을 해야하는 라인이 수십줄이 넘어간다고 상상해보자. 

매크로를 활용하지 못한다면, 각 라인마다 각각 12회의 키를 입력해야 한다.

 

일련의 동작들을 기록하고 재사용할 수 있다면 어떨까? 그게 바로 Vim Macro 이다.

 

Vim Macro

Vim 에서 매크로 등록하고 실행하기

  1. q{레지스터} 로 매크로 기록 시작
  2. q 로 매크로 기록 종료
  3. @{레지스터} 로 저장된 매크로 실행
  4. @@ 로 직전에 실행한 매크로 재실행
  5. {반복횟수}@{레지스터} 또는 {반복횟수}@@ 로 저장된 매크로를 '반복횟수' 만큼 재실행
💡 레지스터는 알파벳(a-z) 또는 숫자(0-9)를 지정할 수 있다. 매크로가 저장되는 레지스터는 복사, 잘라내기 등의 명령에 의해 저장되는 공간과 동일한 공간을 사용하기 때문에 주의하여야 한다. 또한 이를 활용하여 의도적으로 매크로의 내용을 수정할 수도 있다. (아래 [매크로 수정하기] 참고)

q - Vim Macro 기록하기 & 기록 종료하기

Normal Mode 에서 q 를 입력하면, 하단 상태표시줄에 q 가 표시된다. 이는 앞으로 기록할 레지스터를 지정해주기를 대기하고 있는 상태이다. 레지스터(a-z, 0-9 중 하나)를 정하여 입력하면 상태표시줄에 'Recording @a'(레지스터로 'a'를 입력했다고 가정) 와 같이 실제 명령어를 대기하고 있는 상태가 된다. 

 

일련의 동작들을 입력한 뒤 다시 q 를 입력하면 매크로 기록이 종료된다.

 

다음 스크린샷에서 위에서 1~6 과정에서 입력한 과정들을 매크로로 기록하는 과정을 살펴보자.

qa 명령어로 a 레지스터에 일련의 동작들을 기록한 뒤 q 명령어로 기록을 중지했다. (기록상황은 하단 상태표시줄에 나타난다.)

이 예제에서는 매크로를 기록할 레지스터로 a 를 사용했다. 

@ - Vim Macro 실행하기

@{레지스터} 로 특정 레지스터에 저장된 매크로를 실행시킬 수도 있고, @@ 로 직전에 실행한 매크로를 재실행할 수도 있다.

 

"opera" 라인(3번줄)은 @a 로 재실행해보자. 이전 스크린샷에서 그대로 이어진다.

@{매크로가 저장된 레지스터}를 통해 저장된 매크로를 실행시킨다.

 

rock 라인은(4번줄)은 @@ 로 직전에 실행한 매크로를 반복해보자. 이전 스크린샷에서 그대로 이어진다.

(@ 이 두 번 눌러진다는것을 보여주기 위해 @과 @ 사이에 약간의 딜레이를 주었다.)

@@ 는 직전에 실행된 매크로를 재실행한다.

이렇게 매크로를 알아보았다. 사실 이렇게 매크로를 활용하는 것이 거의 전부이다. (쓸 데 없을지도 모르지만) 매크로와 관련하여 몇가지 사항을 아래에서 더 알아보도록 하자. 

레지스터에 저장된 매크로 확인해보기

vim 에서는 레지스터에 저장된 내용을 확인하기 위한 command mode 명령어를 제공한다. :register 가 그것이다. 단순히 이 명령어를 입력하면 모든 레지스터의 저장된 값들을 리스팅해준다. ':register' 명령어는 인자를 받기도 하는데, :register a 와 같이 명령어의 인자로 레지스터명을 전달하면 해당 레지스터에 저장된 값을 표현해준다. (오리지널 vim 에서도 UI 만 다를 뿐 VSCode Vim 과 동일하게 동작한다.)

VSCode Vim 에서 <code>:register</code> 커맨드 모드 명령어로 레지스터의 내용을 확인하는 모습, a 레지스터에 우리가 저장한 동작이 보인다.
<code>:register a</code> 명령어를 입력하여 a 레지스터에 저장된 내용을 확인하는 모습, 우리가 위 과정을 통해 저장한 일련의 동작들이 확인된다.

레지스터에 저장된 내용이기 때문에, 당연하게도 "ap 명령어로 a 레지스터의 내용을 붙여넣을 수 있다. (이게 가능한 이유가 궁금하다면 2021.11.14 - [개발도구/vim] - [The Vim Way] 06 Vim 기본조작 - Vim 복사하기와 붙여넣기 그리고 레지스터 를 참고하도록 하자.)

레지스터를 지정하여("a) 붙여넣기(p)를 수행한 모습이다. 우리가 매크로로 기록했던 내용이 붙여넣어졌다.

매크로는 레지스터에 저장된다는 점을 활용하여 복잡한 매크로의 경우 .vimrc 등의 파일에 등록하여 관리하기도 한다.

매크로 수정하기

  1. 매크로 기록하기
  2. 매크로를 기록한 레지스터의 내용을 새로운 라인에 붙여넣기 ("{레지스터}p)
  3. 매크로 내용 일부 수정하기
  4. 수정한 매크로를 레지스터에 등록하기 (한 줄을 전부 지우면서 등록한다면 "{레지스터}dd)
  5.  매크로 실행하기

레지스터는 yanking(복사) 또는 잘라내기 등이 수행되어 저장되는 레지스터와 동일한 공간을 사용한다. 바로 위 [레지스터에 저장된 매크로 확인해보기]에서 살펴본 것처럼 레지스터에 저장된 내용을 확인할 수 있는데, 레지스터에 텍스트를 등록하는 기능(가령 복사나 삭제)을 활용하여 매크로를 수정할 수 있다. 위 리스트에서는 한 줄 삭제(dd)를 활용하여 수정한 시퀀스를 다시 레지스터에 등록하는 과정을 보여주고 있다.

Vim Macro 활용하기

반복자와 함께 활용하기

매크로도 하나의 명령이기 때문에, 매크로를 실행하기 전에 반복횟수를 지정할 수 있다. 

 

단어와 단어는 tab 문자로 구분되어있는 다음과 같은 데이터가 있다. 

1	one	first
2	two	second
3	three	third
4	four	fourth
5	five	fifth
6	six	sixth
7	seven	seventh
8	eight	eighth
9	nine	ninth
10	ten	tenth
11	eleven	eleventh
12	twelve	twelfth
13	thirteen	thirteenth
14	fourteen	fourteenth
15	fifteen	fifteenth
16	sixteen	sixteenth
17	seventeen	seventeenth
18	eighteen	eighteenth
19	nineteen	nineteenth
20	twenty	twentieth
21	twenty-one	twenty-first
22	twenty-two	twenty-second
23	twenty-three	twenty-third
24	twenty-four	twenty-fourth
25	twenty-five	twenty-fifth
26	twenty-six	twenty-sixth
27	twenty-seven	twenty-seventh
28	twenty-eight	twenty-eighth
29	twenty-nine	twenty-ninth
30	thirty	thirtieth
31	thirty-one	thirty-first
40	forty	fortieth
50	fifty	fiftieth
60	sixty	sixtieth
70	seventy	seventieth
80	eighty	eightieth
90	ninety	ninetieth
100	one hundred	hundredth

이 데이터를 가공하여 각 라인을 다음과 같이 처리하고자 한다. 

// from
1	one	first

// to
const ONE = 1; // first number

이를 매크로를 기록하고 모든 라인에 적용해보도록 하자.

먼저 기록하는 화면을 보도록 하자.

첫번째 줄을 요구사항대로 가공하는 동작을 매크로에 기록하는 장면

이제 이 매크로를 나머지 라인들에 적용해보자.

100@@ 로 나머지 라인들에 대해 매크로를 일괄 적용할 수 있다.

이와 같이 '충분한' 숫자를 반복횟수로 지정하여 남아있는 처리 대상에 대해 매크로가 적용되게 할 수 있다. 매크로는 더 이상 진행될 수 없으면 그 동작을 멈추므로 실제로는 37 라인밖에 되지 않지만, 100@@ 와 같이 '충분한' 반복횟수를 지정하는 것으로 편리하게 '나머지 대상 전부'를 지정할 수 있다.

 

위 스크린샷의 경우처럼 100 의 경우 그 처리가 제대로 되지 않은것을 확인할 수 있는데(one hundred 만 이름 사이에 공백이 들어가있음), 매크로를 기록할 때 이러한 다양한 상황까지 고려하여 작성해주어야 할 필요가 있을 수 있다.  


매크로는 동일한 이름을 공유하는 마이크로 매크로(dot command)보다는 그 활용도가 낮다고 할 수 있다. 매크로는 위에서 본 것과 같이 '복잡한 시퀀스'를 '여러번 수행'하여야 할 때 그 진가를 발휘한다. 간혹 코딩을 하다보면, 이러한 요구사항이 생기기 마련인데, 그럴 때마다 vim 에서 macro 를 어떻게 수행했는지 검색해보면 그만이다. 그러니 부담을 갖지 말고, 그러한 상황에 매크로가 있었다는 사실을 기억하고 적용해볼 수 있었으면 좋겠다. 

 

다음 시간에는 커맨드모드에서 수행할 수 있는 다양한 명령어 중에 하나인 (그리고 사실 이 연재에서 다루는 몇 안되는 커맨드모드 명령어중에 하나인) '찾아바꾸기' 기능을 소개하도록 하겠다.

반응형

Designed by JB FACTORY