ex-command를 사용하여 두 줄이 동일한 지 확인하십시오.


9

나는 이 질문 을보고 순수 POSIX 를 사용sed 하는 내 대답을 어떻게 구현할 수 있는지 궁금해했다 .ex

요령은 sed홀드 공간과 패턴 공간을 비교하여 패턴 공간과 정확히 같은지 여부를 확인할 수는 있지만 (와 G;/^\(.*\)\n\1$/{do something}) 같은 테스트를 수행 할 방법이 없다는 것입니다 ex.

나는 빔에 내가 할 수있는 것을 알고 Y첫 번째 줄을 ANK 다음 입력 :2,$g/<C-r>0/d에 거의 내가 지정-그러나있어 일을 첫 번째 줄은 아무 것도 포함하지만 라인이로 덤프되는 때문에 매우 간단 영숫자 텍스트이, 참으로 위태로운이되면 정규식 비교 용 문자열이 아닙니다. (그리고 첫 번째 줄에 슬래시가 있으면 나머지 줄은 명령으로 해석됩니다!)

따라서 myfile첫 번째 줄과 동일한 모든 줄을 삭제하고 싶지만 첫 번째 줄은 삭제하지 않으려면 어떻게해야 ex합니까? 그 문제에 대해 어떻게 사용할 수 vi있습니까?

다른 줄과 정확히 일치하는 줄을 삭제하는 POSIX 방법이 있습니까?

아마도이 가상 구문과 같은 것입니다 :

:2,$g/**lines equal to "0**/d

3
명령을 작성할 수는 있지만 약간의 vimscript가 필요할 것이며 아마도 POSIX 방식이 아닐 것입니다.:execute '2,$g/\V' . escape(getline(1), '\') . '/d'
— saginaw

1
@saginaw, 감사합니다. 지금까지 나에게 일어난 유일한 POSIX 접근 방식 은 within 에서 필터sed 로 사용 하고 전체 버퍼에 대한 전체 대답을 실행 하는 것 입니다. 물론 작동 할 것 입니다 (실제로는 이식성이 없습니다 ). exsedsed -i
— 와일드 카드

당신 말이 맞아요. 나는 당신의 초기 접근 방식이 <C-r>0아주 좋습니다. 특수 문자를 보호해야하기 때문에 Ex 명령으로 만 더 잘 수행 할 수 있는지 확실하지 않습니다. POSIX 호환 제약 조건이 없으면 매우 nomagic 스위치를 사용하고 두 번째 인수가 이스케이프 / 보호하려는 모든 문자가 포함 된 문자열 인 함수로 \V백 슬래시를 보호 한다고 생각합니다 (와도 특별한 의미를 유지하기 때문에 \V) escape().
— saginaw

그러나 이전 명령에서 슬래시도 보호하는 것을 잊었습니다. 전역 명령에도 특별한 의미가 있기 때문에 패턴 구분 기호입니다. 따라서 올바른 명령은 다음과 같습니다. :execute '2,$g/\V' . escape(getline(1), '\/') . '/d'또는 세미콜론과 같이 패턴 구분 기호에 다른 문자를 사용할 수 있습니다. 이 경우 패턴에서 슬래시를 보호 할 필요가 없습니다. : 그것은 같은 줄 것이다:execute '2,$g;\V' . escape(getline(1), '\') . ';d'
— 새 기노

1
나는 당신의 두 번째 접근법 sed도 매우 좋습니다. Vim을 사용하면 특정 특수 작업을 다른 프로그램에 위임하는 경우가 많으며 이에 sed대한 좋은 예일 것입니다. 그건 그렇고, 당신은 sed전체 버퍼 에서 실행할 필요가 없습니다 . 버퍼의 일부에서만 실행하려는 경우 범위를 지정할 수 있습니다. 예를 들어 50과 100 사이의 행만 필터링하려면 다음과 같이 입력하십시오 :50,100!<your sed command>..
— saginaw

답변:


3

정력

Vim에서는 개행 문자를 포함한 모든 문자를로 일치시킬 수 있습니다 \_.. 이것을 사용하여 전체 라인, 임의의 양, 동일한 라인과 일치하는 패턴을 구성 할 수 있습니다.

/\(^.*$\)\_.*\n\1$/

이제 파일에서 첫 번째를 포함하지 않고 첫 번째와 일치하는 모든 행을 삭제하려고합니다. 첫 번째 줄과 일치하는 마지막 줄을 삭제하는 대체 방법은 다음과 같습니다.

:1 s/\(^.*$\)\_.*\zs\n\1$//

:global대체를 반복하여 모든 행을 삭제하기에 충분한 횟수를 반복하도록 할 수 있습니다 .

:g/^/ 1s/\(^.*$\)\_.*\zs\n\1$//

POSIX 예

@saginaw는 귀하의 질문에 대한 의견으로 Vim 에서이 작업을 수행하는 더 좋은 방법을 보여 주지만 위의 기술을 POSIX ex에 적용 할 수 있습니다.

POSIX 호환 방식으로이 작업을 수행하려면 여러 줄 일치를 허용하지 않아도 역 참조를 계속 사용할 수 있습니다. 추가 작업이 필요합니다.

:g/^/ t- | s/^/@@@/ | 1t- | s/^/"/ | j! | s/^"\(.*\)@@@\1$/d/ | d x | @x

고장은 다음과 같습니다.

:g/^/                   for each line

t- |                    copy it above

s/^/@@@/ |              prefix it with something unique (@@@)
                        (do a search in the buffer first to make
                        sure it really is unique)

1t- |                   copy the first line above this one

s/^/"/ |                prefix with "

j! |                    join those two lines (no spaces)

s/^"\(.*\)@@@\1$/d/ |   if the part after the " and before the @@@
                        matches the part after the @@@, replace the line
                        with d

d x |                   delete the line into register x

@x                      execute it

따라서 현재 행이 행 1의 복제본이면 레지스터 x에가 포함 d됩니다. 실행하면 현재 줄이 삭제됩니다. 중복되지 않은 경우 주석을 시작하기 "때문에 실행될 때 no-op가 아닌 넌센스 접두사가 포함 "됩니다. 이것이 가장 달성하기 어려운 방법인지는 모르겠습니다. 처음 떠오른 것입니다!

복사 프로세스가 1 행을 일시적으로 변경하기 때문에 첫 번째 행을 삭제할 수 없습니다. 이 경우하지 않았다면 당신은 접두사 수 :g로모그래퍼 2,$대신 범위.

Vim 및 ex-vi 버전 4.0에서 테스트되었습니다.

편집하다

그리고 더 간단한 방법은 특수 문자를 이스케이프하여 검색 패턴 ( 'nomagic'설정된)을 작성하고 :global명령 을 작성한 다음 실행합니다.

:set nomagic
:1t1 | .g/^/ s#\[$^\/]#\\\&#g | s#\.\*#2,$g/^\&$/d# | d x
:@x
:set magic

중첩 된을 가질 수 있기 때문에 하나의 라이너 로이 작업을 수행 할 수 :global는 없습니다.


2

이 작업을 수행하는 유일한 POSIX 방법은와 같은 외부 필터를 사용하는 것 같습니다 sed.

예를 들어 파일의 다섯 번째 줄과 정확히 동일한 경우에만 파일의 17 번째 줄을 삭제하고 변경하지 않은 상태로 두려면 다음을 수행하십시오.

:1,17!sed '5h;17{G;/^\(.*\)\n\1$/d;s/\n.*$//;}'

( sed여기에서 전체 버퍼에서 실행하거나 5-17 행에서만 실행할 수 있지만 첫 번째 경우에는 불필요한 필터링을 수행합니다. 별다른 문제는 없으며 후자의 경우 sed5와 17 대신 명령 에 숫자 1과 13. 혼란.)

sed하나의 정방향 패스 만 수행 하므로 , 17 행과 동일한 경우에만 5 행을 역으로 삭제하고 삭제할 수있는 쉬운 방법이 없습니다. 나는 호기심의 지점으로 잠시 동안 노력했다 ... 그것은 까다 롭다 .


혁신 -다음과 같이 할 수 있습니다.

:17t 5
:5,5+!sed '1N;/^\(.*\)\n\1$/d;s/\n.*$//'

이것은 실제로 더 일반적인 방법입니다. 마찬가지로 첫 번째 명령과 동일한 결과를 제공하고 (5 번째 줄과 동일한 경우에만 17 번째 줄을 삭제) 다음과 같이 사용할 수 있습니다.

:5t 17
:17,17+!sed '1N;/^\(.*\)\n\1$/d;s/\n.*$//'

37 행과 동일한 파일의 모든 행을 삭제 하고 37 행은 그대로두고 더 광범위하게 사용 하려면 다음을 수행하십시오.

:37,$!sed '1{h;n;};G;/^\(.*\)\n\1$/d;s/\n.*$//'
:37t 0
:1,37!sed '1{h;d;};G;/^\(.*\)\n\1$/d;s/\n.*$//'

결론은 여기에 두 개의 라인이 동일한 경우, 가장 좋은 도구 검사를 들면, 이다 sed ,하지 ex. 그러나 DevSolar 코멘트에 언급 ,이의 실패하지 vi나 ex- 그들은이되는 설계 유닉스 도구를 사용하여 작업에; 그것은 큰 힘입니다.


훨씬, 훨씬 어렵습니다 : 행이 존재하지 않는 경우에만, 파일의 끝에 행을 삽입 어딘가에 파일에.
— 와일드 카드

그것은 내 대답과 비슷한 접근법으로 가능해야합니다. 나는 그것이 하나의 라이너 일 것이라고 생각하지 않습니다!
— Antony
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.