줄 순서를 바꾸는 방법?


24

첫 번째 줄이 끝에 나타나고 마지막 줄이 먼저 나타나도록 줄 순서를 바꾸려면 어떻게해야합니까? (버퍼의 모든 라인, 주소 범위 또는 라인 단위 비주얼 모드 선택 일 수 있습니다.)

변신하고 싶습니다

rat
ox
tiger
⋮
dog
pig

으로

pig
dog
⋮
tiger
ox
rat

와 같은 외부 명령에 의지하지 않고 tac.


이 질문에 더 나은 태그에 대한 제안 사항이 있습니까?
— 200_success

1
새로운 'pure-vi'또는 이와 유사한 태그일까요? 외부 도구를 사용하지 않으려는 태그를 통해 얻을 수있는 몇 가지 질문을 보았습니다. 메타에 대해 물어봐야합니까?
— John O'M.

1
@Carpetsmoker (그리고 이것에 관심이있는 다른 사람들) 태그 질문은 이제 meta meta.vi.stackexchange.com/questions/1229/…
— John O'M에 있습니다.

답변:


29

글로벌의 힘은 여기에서 작동합니다 :

:g/^/exe "normal ddggP"

또는 더 간단히 말하면 (@tommcdo 덕분에)

:g/^/move 0

첫 번째는 모든 행과 각 행과 일치하며 삭제하고 파일 맨 위에 붙여 넣습니다. 파일을 이동할 때 텍스트를 반대로 바꿉니다.

두 번째는 마찬가지로 모든 줄과 일치하여 파일의 맨 위로 이동합니다.

참고 :이 두 파일 은 전체 파일 에서 작동 하며 행의 서브 세트를 뒤집는 데 올바르게 적용되지 않습니다. 범위 내에서 작동하는 솔루션에 대해서는 Ingo Karkat의 답변 을 참조하십시오 .

기술:

g글로벌 명령은
/^/시작에 (즉, 모든 선)이있는 라인과 일치하는
exe다음 문자열을 실행
"normal일반 모드 명령을 수행
dd삭제 라인
gg파일의 상단으로 이동
P현재 위치 위에 붙여 넣기

move 0 현재 행을 0 행 아래로 이동합니다 (1 위치 또는 파일의 첫 번째 행에 위치)


6
:normal명령 대신 Ex 명령을 사용 :move 0하면 행이 버퍼의 시작 부분으로 이동합니다.
— tommcdo

1
또한 :execute명령을 동적으로 빌드해야하는 경우에만 필요합니다 (예 :) :execute 'normal' g:user_command.
— tommcdo

@tommcdo 좋은 포인트! 나는 :execute기존의 명령 후에 다른 Ex 명령을 종종 추가하기 때문에 사용 습관이 있습니다 :exe. 나중에 나중에 다시 삽입 해야하는 것보다 이미 거기 에있는 것이 더 편리합니다 . 불행히도, 그 습관은 그 답이 많이 적용되지 않는 곳에서이 답변으로 유출되었습니다.
— John O'M.

1
내 사용에 대한 자세한 설명 :execute: 문자열을 사용하기 때문에 문자열을 구성하지 않더라도 일반 모드 명령이 끝나는 위치를 명확하게 설명합니다. 찾는 것보다 균형 잡힌 따옴표를 찾는 것이 더 쉽습니다. <esc>또는 모드를 종료하기 위해 무엇이든. 다시, 이것은 개인적인 취향과 습관입니다. :-)
— John O'M.

3
이것은 btw 범위에서 작동합니다 : :9,11g/^/move 8... 마지막 숫자는 범위 -1의 시작이어야합니다 (Ingo의 대답에서 적응).
— Martin Tournoij

13

이 one-liner ( ~/.vimrc)는 :Reverse명령을 정의합니다 . :global부품을 직접 사용할 수도 있지만 :move(범위 시작 전에 줄을 반복적으로 이동시켜 반전시키는) 구문은 기억하기 쉽지 않습니다.

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1

1
독자를위한 참고 자료로서 <line1>& <line2>는이 작업을 다양한 범위에서 수행해야합니다 :7,9Reverse( 예 :의 기능은 또는 command아닙니다 ). 더 간단한 것도 작동하지만 전체 버퍼에만 적용됩니다.globalmove:command! -bar -range=% Reverse :global/^/m 0
— Martin Tournoij

6

순수한 Vim :

:g/^/m0

설명:

에 따르면 :help multi-repeat, :g그 사촌 :v은 두 가지 방식으로 작동합니다.

첫 번째 패스 패스는 :g모든 행과 일치 {pattern}하며 두 번째 패스 (파일의 시작에서 시작하여 끝까지 진행되는 것으로 명백히 수행됨)는을 수행합니다 [cmd]. 위의 사용은 :g라인이 처리되는 순서를 이용합니다 (기술적으로 보장되지는 않지만 괜찮을 것입니다).

먼저 모든 줄을 표시 한 다음 첫 번째 표시된 줄을 파일의 상단으로 이동 한 다음 두 번째 줄을 파일의 상단으로 이동 한 다음 (이전에 이동 한 줄 위), 세 번째 표시된 줄 (이전에 이동 한 것 이상)으로 작동합니다 파일의 마지막 줄이 맨 위로 이동하여 파일을 효과적으로 되돌릴 때까지 계속 진행합니다.

:g위에서 아래로가 아닌 다른 순서로 행을 처리 하면 이 명령이 작동하지 않습니다.

출처 : vim wikia에서 모든 라인 과 g 의 거듭 제곱을 바꾸십시오.

외부 명령을 사용하는 몇 가지 예 :

  • tac( GNU coreutils의 일부 - cat반대) :

    :%!tac                                                                                                                                                                                                                                                              
    
  • tail BSD / OSX (POSIX 호환 아님) :

    :%!tail -r
    

    -r -r 옵션을 사용하면 입력이 라인별로 역순으로 표시됩니다.

    man tar자세한 내용은 확인 하십시오.

자세한 아이디어는 다음을 참조하십시오.


2
하지인가 :g/^/m0와 같은 :g/^/move 0존의 대답 인?
— muru

@muru 그렇게 생각하지만 이것은 vim wikia에 따르면 더 짧으며 명령 줄 사용에 대한 몇 가지 추가 예제로 다른 설명을 추가했습니다.
— kenorb

예, 다른 명령으로 인해 투표했습니다 (게시물이 나왔습니다 tac). 그러나 나는 downvote가 답이 반복되기 때문이라고 생각합니다.
— muru

나는 tacOP가 언급 한 것을 알고 있지만 다른 모든 유사한 질문은 이것과 중복 될 것이므로 다시 언급하는 것이 좋습니다. John은 @tommcdo 주석 에서이 cmd를 가져 왔으며 처음에는 DerMike 에서 가져 왔습니다 .하지만 단순히 Wikia에서 가져온 것으로 생각하므로 vim wikia에 크레딧을 주었으므로 설명이 완전히 다르기 때문에 완전히 복제되지 않았습니다.
— kenorb

적절한 설명으로 훨씬 짧은 버전이므로 더 많은 가치가 추가되고 올바른 소스를 제공하고 있습니다. 쉘 명령을 사용하는 것은 매우 간단하고 편리합니다. 사람들이 동의하지 않으면, 단순히 투표권을 행사할 수 있습니다.
— kenorb

6

기능성 VimL의 정신에서 :

:call setline(1, reverse(getline(1, line('$'))))
  • getline(1, line('$'))버퍼 내의 모든 행의리스트를 돌려줍니다. 버퍼의 마지막 행을 나타내는 '$'특수 인수입니다 line().
  • reverse(...)입력 목록을 제자리로 되돌립니다. 하나는 사용해야합니다 reverse(copy(...))입력 목록이 수정되지 않아야합니다.
  • setline(1, ...)지정된 줄을 두 번째 인수로 바꿉니다. 두 번째 인수가 목록 인 경우 목록의 길이와 동일한 행 수가 목록의 내용으로 바뀝니다.

원하는 경우 범위를 갖는 명령을 정의 할 수도 있습니다 (기본 %전체 버퍼).

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))

1
나는이 답변을 좋아한다. 또한 다른 답변 hlsearch의 :g/명령 과 같은 내용 ( 사용 가능한 경우 )을 강조 표시하지 않습니다 ...하지만 성능이 떨어질 수 있습니까? getline(1, line('$'))메모리의 전체 버퍼를 가져 오기 때문 입니다. reverse()제자리에있는 것처럼
— 보이므로

3

Vim 문서에 따라 usr_12.txt-Clever Tricks

12.4 역순

:global명령이와 결합 될 수있다 :move반전 된 파일의 결과로, 첫 번째 라인 전에 모든 라인을 이동하는 명령. 명령은 다음과 같습니다.

:global/^/m 0

약식 :

:g/^/m 0

^정규 표현식은 라인 (라인이 비어있는 경우에도)의 시작과 일치합니다. 이 :move명령은 일치하는 줄을 신화적인 0 번째 줄 다음으로 이동하므로 현재 일치하는 줄은 파일의 첫 번째 줄이됩니다. 는 AS :global명령이 변화하는 라인 번호에 의해 혼동되지 않으며, :global파일 및 첫 번째로 박았 각각의 남아있는 모든 라인을 일치로 진행한다.

이것은 또한 다양한 라인에서 작동합니다. 먼저 첫 번째 줄 위로 이동하여로 표시하십시오 mt. 그런 다음 커서를 범위의 마지막 줄로 이동하고 다음을 입력하십시오.

:'t+1,.g/^/m 't

1

상대 숫자를 사용합니다. 단락은 13 행에서 시작하여 4 행 이상 스팸

 :13,13+4g/^/m12
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.