johngrib / johngrib.github.io

my wiki
MIT License
76 stars 42 forks source link

[질문] awk 가 원하는대로 동작하지 않는 문제 #211

Closed GuruneLee closed 1 year ago

GuruneLee commented 1 year ago

안녕하세요 기계인간님, 블로그 잘 보고있는 초보 개발자 입니다...! 읽고 있는 책의 진행도를 Vim에서 자동으로 계산하자를 따라해보고, 잘 안돼서 이것저것 시도해봤지만 문제가 해결되지 않아 질문드립니다

일단 다음과 같이 스크립트를 변경해서, 원하는 타이밍에 함수가 잘 실행되는 것은 확인했습니다.

function! UpdateBookProgress()
    let l:save_cursor = getpos(".")
    " \d+ % : \d+ / \d+ 형식의 라인을 삭제한다
    %g,\v^\d+ \% : \d+ \/ \d+,d
    call setpos('.', l:save_cursor)
endfunction

augroup book
    autocmd BufWritePre *.md call UpdateBookProgress()
augroup END

그런데, awk 명령어가 잘 실행이 안됩니다. 다음과 같이 vim 파일에 직접 실행을 해봐도 원하는 동작을 하지 않습니다. https://user-images.githubusercontent.com/60911416/198350134-895ef52d-ef1b-42a6-b4e6-359555450220.mov

혹시 몰라 제 vimrc 전문을 남깁니다. 도움 주시면 너무너무 감사할 것 같습니다. 감사합니다. 좋은 하루 되세요.

call plug#begin()
  Plug 'vimwiki/vimwiki', { 'branch': 'dev' }
  Plug 'mhinz/vim-startify'
call plug#end()

set encoding=utf-8
set fileencodings=utf-8,cp949
set hlsearch
set smartcase
set ruler
set autoindent
set cindent

" set nu

set ts=2
set shiftwidth=2

au BufReadPost *
\ if line("'\"") > 0 && line("'\"") <= line("$") |
\ exe "norm g`\"" |
\ endif

syntax on

" vimwiki 설정
let maplocalleader = "\\"
let g:vimwiki_list = [
  \{
  \   'path': '~/workplace/vimwiki',
  \   'ext' : '.md',
  \   'diary_rel_path': '.',
  \},
\]

let g:vimwiki_conceallevel = 0
let g:vimwiki_global_ext = 0

nmap <LocalLeader>ww <Plug>VimwikiIndex

" vimwiki book
function! UpdateBookProgress()
    let l:save_cursor = getpos(".")
    " \d+ % : \d+ / \d+ 형식의 라인이 있으면 퍼센테이지를 계산해 업데이트한다
    let l:awk_command = "awk '{print int($4 * 100 / $6), \"\\% :\", $4, $5, $6 }'"
    %g,\v^\d+ \% : \d+ \/ \d+,d
    call setpos('.', l:save_cursor)
endfunction

augroup book
    autocmd BufWritePre *.md call UpdateBookProgress()
augroup END
johngrib commented 1 year ago

@GuruneLee 님 여기를 보면 awk 명령 문자열을 만들어서 l:awk_command 변수에 넣어두는데, 변수에만 넣어두고 명령을 실행하지 없어서 효과가 없는 것 같아요.

image

제가 예전에 작성해 둔 문서를 참고하자면...

image

exe "normal! V! 뒤에 l:awk_command를 붙여서 실행하고 있습니다. 이 구문이 빠져서 안 되는 것으로 보입니다. ( @GuruneLee 님의 코드를 보면 g 마지막 옵션으로 삭제를 의미하는 d 를 붙이고 있어 업데이트가 아니라 삭제가 되고 있을 것 같네요)

만약 awk 문법에 익숙하지 않아 어려움을 느끼신다면 평소 익숙하게 사용하고 있는 다른 프로그래밍 언어(javascript라던가)로 변환기를 만들어 호출하셔도 됩니다.


한편, 문의하신 방법은 제가 옛날에 사용하던 것으로 저는 요즘은 다른 방법을 사용하고 있습니다. 이 작업을 하는 코드를 별도의 셸 스크립트로 분리해서 쓰고 있어요.

다음 링크에서 셸 스크립트를 볼 수 있습니다. https://github.com/johngrib/dotfiles/blob/1219b6609c6fe0cf69b09f770935a4fdac611032/nvim/vim-include/bookProgressUpdate.sh

이걸 UpdateBookProgress 함수에서 호출해서 쓰고 있죠. 아래 링크를 보시면 호출하는 방법을 보실 수 있습니다. https://github.com/johngrib/dotfiles/blob/1219b6609c6fe0cf69b09f770935a4fdac611032/nvim/vim-include/set-vimwiki.vim#L141-L145

GuruneLee commented 1 year ago

답변 감사합니다

먼저, 'd' 를 붙였기에 실행이 안됐다고 말씀해주신 부분은 제가 스크립트가 동작은 하는지 테스트하기위해 바꿔놨던 것입니다. (테스트 후 원복시키지 않아서 오해가 있었네요 ㅎ..)

다음과 같이 블로그 대로 따라서 해봐도 원하는대로 동작을 하지 않습니다.

" vimwiki book
function! UpdateBookProgress()
    let l:save_cursor = getpos(".")
    " \d+ % : \d+ / \d+ 형식의 라인이 있으면 퍼센테이지를 계산해 업데이트한다
    let l:awk_command = "awk '{print int($4 * 100 / $6), \"\\% :\", $4, $5, $6 }'"
    %g,\v^\d+ \% : \d+ \/ \d+,exe "normal! V!" . l:awk_command . "^M"
    call setpos('.', l:save_cursor)
endfunction

augroup book
    autocmd BufWritePre *.md call UpdateBookProgress()
augroup END

또한, vim 파일 내부로 직접 접근해서 직접 커맨드를 입력해도 원하는대로 동작하지 않습니다 ( 정확히는, 텍스트가 바뀌지 않습니다 )

image

그래서 질문을 요약 드리자면

  1. 블로그에서 소개해주신 g와 awk 를 이용한 커맨드가 잘 동작 하나요?
  2. normal! 은 vim normal 모드로 진입하는 명령어임을 알았는데, V! 는 어떤 명령어 인가요?

감사합니다.


쉘 스크립트를 이용한 방식은 따로 시도해보겠습니다! 소개해주셔서 감사합니다 ㅎㅎ

johngrib commented 1 year ago

답변 감사합니다

먼저, 'd' 를 붙였기에 실행이 안됐다고 말씀해주신 부분은 제가 스크립트가 동작은 하는지 테스트하기위해 바꿔놨던 것입니다. (테스트 후 원복시키지 않아서 오해가 있었네요 ㅎ..)

다음과 같이 블로그 대로 따라서 해봐도 원하는대로 동작을 하지 않습니다.

" vimwiki book
function! UpdateBookProgress()
    let l:save_cursor = getpos(".")
    " \d+ % : \d+ / \d+ 형식의 라인이 있으면 퍼센테이지를 계산해 업데이트한다
    let l:awk_command = "awk '{print int($4 * 100 / $6), \"\\% :\", $4, $5, $6 }'"
    %g,\v^\d+ \% : \d+ \/ \d+,exe "normal! V!" . l:awk_command . "^M"
    call setpos('.', l:save_cursor)
endfunction

augroup book
    autocmd BufWritePre *.md call UpdateBookProgress()
augroup END

또한, vim 파일 내부로 직접 접근해서 직접 커맨드를 입력해도 원하는대로 동작하지 않습니다 ( 정확히는, 텍스트가 바뀌지 않습니다 ) image

그래서 질문을 요약 드리자면

  1. 블로그에서 소개해주신 g와 awk 를 이용한 커맨드가 잘 동작 하나요?
  2. normal! 은 vim normal 모드로 진입하는 명령어임을 알았는데, V! 는 어떤 명령어 인가요?

감사합니다.

쉘 스크립트를 이용한 방식은 따로 시도해보겠습니다! 소개해주셔서 감사합니다 ㅎㅎ

  1. 네. 잘 동작합니다. 제가 오랫동안 써왔던 방법이기도 하고요. %g,\v^\d+ \% : \d+ \/ \d+,d16 % : 47 / 279도 문제없어 보이고, 실제로 해보니 잘 동작하네요.
  2. V 는 라인 비주얼 모드이고, !는 뒤에 셸 명령을 실행하기 위한 prefix 입니다. g 로 책 진도가 표시된 라인을 골라낸 다음 V로 비주얼 모드로 선택하고 ! 뒤에 있는 명령을 실행하는 거죠.
  3. 써놓고 보니 한 가지 문제점이 보입니다. ^M을 입력할 때 ^M을 두 글자로 입력해서 넣으신 것 같아요. 그런데 저건 두 글자가 아니라 실제로는 CR로 한 글자입니다. ^M즉 CR 은 키보드의 키로 따지자면 엔터 키라 할 수 있고, 조합을 말하자면 ctrl+m 인데요, 보통 다른 에디터에서는 그냥 엔터로만 취급해서 개행문자로만 보이게 되고 눈으로는 안 보이죠. 그런데 터미널에서는 이걸 보이게 하는 방법이 있어요. ctrl+v를 입력한 다음 ctrl+m을 입력해 넣을 수 있는 것입니다. Vim도 평범한 터미널에서 돌아가는 애플리케이션이므로 이 방법을 써서 입력할 수 있죠. 즉 ^M은 awk 커맨드를 입력한 다음 엔터 키를 누르라는 뜻입니다.

저는 ^M을 쓰는 게 익숙해서 그냥 저렇게 썼는데, 문제가 이것 때문인 것 같습니다. ^M 의 사용이 어렵게 느껴지거나 잘 모르겠다면 개행문자를 입력하는 가장 흔한 방법인 \n(LF)을 쓰는 것도 방법입니다.

즉 여길 이렇게 하는 거죠.

    %g,\v^\d+ \% : \d+ \/ \d+,exe "normal! V!" . l:awk_command . "^M"
    %g,\v^\d+ \% : \d+ \/ \d+,exe "normal! V!" . l:awk_command . "\n"

물론 이렇게 해서 CR을 입력해도 작동할 것입니다.

    %g,\v^\d+ \% : \d+ \/ \d+,exe "normal! V!" . l:awk_command . "\r"
GuruneLee commented 1 year ago

으아! 감사합니다!! 드디어 동작합니다 ㅠㅠㅠ

친절하게 답변해주셔서 감사합니다... 갖가지 시도를 해보다가 도저히 모르겠어서 질문 드린건데, 빨리 질문 드릴걸 그랬습니다..ㅎ.. 이렇게 또 새로운 사실 배워가서 너무 즐겁네요

심심할 때 마다 블로그 글 랜덤으로 돌려서 보고있습니다. 감사합니다. 행복한 주말 되세요!!