특정 부분을 복사하고 변경하여 파일의 내용을 조작하는 방법은 무엇입니까?

특정 부분을 복사하고 변경하여 파일의 내용을 조작하는 방법은 무엇입니까?

텍스트 파일을 조작하고 싶습니다. 다음과 같은 형태의 블록이 많이 포함되어 있습니다.

CLASS
   ...some stuff ...
END

각 블록을 복사하고 해당 내용의 한 줄을 추가 및 제거하고 싶습니다. 스크립트를 작성할 수 있나요?

답변1

알았어 너할 수 있는무엇이든 쓰세요.

그러나 이렇게 하면 vim매크로를 사용하게 됩니다. (아직 익숙하지 않다면 vim배워야 하고, 그렇지 않다면 무시하세요)

몇 가지 기본 지침:

q - 매크로 기록 시작

qx -- 매크로 기록을 중지하고 이름을 "x"로 지정합니다.

@x -- "x"라는 매크로를 실행합니다.

매크로는 기록 세션 중에 입력한 모든 명령을 즉시 다시 실행합니다.

따라서 매크로가 다음과 같이 블록을 복사하도록 하려면:

q          start macro
/CLASS     jump to next "CLASS"
V          start selecting full lines
/END       jump to next "END
Y          yank selected lines (yank = copy)
j          scroll down one line
p          put (paste)
qd         stop recording and name the macro d

vim 사용법과 vim 매크로에 대한 좋은 리소스와 예제가 많이 있습니다.

가치 있는 점은 sed가 vim의 명령줄 버전이기 때문에 내가 말하는 내용을 sed에 적용할 수 있을 수도 있지만, 저는 그것에 익숙하지 않기 때문에 보장할 수 없습니다.

~~편집~~

더 유용하게 만드는 또 다른 점은 vim여러 파일을 열 수 있다는 것입니다. 여러 개의 열린 파일을 버퍼라고 합니다. 여러 파일 이름을 추가하여 이 기능을 활성화할 수 있습니다 vim(IE는 vim *.txt모든 txt 파일을 엽니다).

여러 버퍼에서 매크로를 실행하려면 먼저 모든 파일을 동시에 엽니다. 그런 다음 각 버퍼에서 :bufdo normal @x매크로 실행을 사용하십시오.x

:w현재 버퍼가 저장되지 않은 경우 다음 버퍼로 전환하려고 시도하는 동안 중단되는 것을 방지하려면 이 단계를 매크로의 마지막 단계로 만들어야 합니다 .

:bn수동으로 다음 버퍼로 이동합니다.

또한보십시오https://stackoverflow.com/questions/1291962/replay-a-vim-macro-until-end-of-buffer각 행에 대해 매크로를 실행하는 방법을 알아보세요. 리안리안칸 :)

답변2

이 목적을 위한 자연스러운 도구는 awk와 Perl입니다(스크립트를 작성한다고 가정하면 일회성이며 자연 도구는 대화형 편집기입니다). 다음은 모든 CLASS... 블록을 복사하는 awk 스크립트입니다 END(균형 조정 지원 안 함: 각 블록이 CLASS다음 블록과 일치함 END). 그러나 foo두 번째 복사본에서는 줄이 생략됩니다.

awk '
  /^CLASS$/ { store = 1; }  # start storing
  store && ! /^foo$/ { hold = hold ORS $0; }  # if storing, maybe save line
  /^END$/ {
      $0 = $0 hold;  # append hold copy to current line
      store = 0; hold = "";  # end of block
  }
  1 { print; }  # print original line, with hold prepended if at end of block
'

이것은 sed 솔루션입니다. 너무 심각하게 받아들이지 마십시오. CLASS/ 줄이 엄격하게 번갈아 표시되지 않으면 작동할 것이라고 기대하지 마세요 END.

sed -e '/^CLASS$/,/^END$/!b' \
    -e '/^CLASS$/{' -e 'h' -e 'b' -e '}' \
    -e '/^foo$/!H' \
    -e '/^END$/G'

답변3

사용되는 정확한 도구는 작업의 세부 사항에 따라 다릅니다. 작업이 한 번만 발생하는 경우 vim또는 에서 매크로 사용을 고려할 수 있습니다 emacs. 정말로 스크립트를 작성하고 싶다면 다음을 살펴보겠습니다 sed.

Sed는 스트림 편집기입니다. 스트림 편집기는 입력 스트림(파일 또는 파이프의 입력)에서 기본 텍스트 변환을 수행하는 데 사용됩니다.

이 작업을 수행하는 정확한 방법은 상황에 따라 다르지만 PATTERN으로 시작하는 줄 뒤에 줄을 추가하려면 다음을 수행할 수 있습니다.

sed -e 's/\(^PATTERN.*\)/\1\nTextToAdd/' file.old > file.new

PATTERN으로 시작하는 줄 앞에 줄을 추가하려면 다음을 수행하세요.

sed -e 's/\(^PATTERN.*\)/TextToAdd\n\1/' file.old > file.new

PATTERN으로 시작하는 줄 삭제

sed -e 's/\(^PATTERN.*\)//' file.old > file.new

비결은 원하는 선만 캡처할 수 있는 올바른 패턴을 찾는 것입니다.

다음을 수행하여 이를 결합할 수 있습니다.

sed -e 's/\(^PATTERN1.*\)/\1\nTextToAdd/' -e 's/\(^PATTERN2.*\)/TextToAdd\n\1/' file.old > file.new

답변4

내 Python 솔루션:

file = open('a.txt', 'r')
arr = []
tmp = []
remember = False

for line in file:
    if "CLASS" in line:
        remember = True     # start storing lines
        tmp.append(line)    # we're storing lines in list
        continue            # go to next line
    if "END" in line:
        tmp.append(line)    # store line
        remember = False    # stop storing lines
        arr.append(tmp)     # add line to list
        tmp = []            # clear temp list
        continue            # go to next line
    if remember:
        tmp.append(line)    # add to list line between CLASS and END
file.close()

file = open('a.txt', 'a')
for tmp in arr:
    if '   ...some stuff ...1\n' in tmp:    # we can skip 
        continue                            # whole block if we find this
    for i in tmp:
        if "333" in i:  # we can skip only one line 
            continue
        file.write(i)
file.close()

awk 버전보다 이해하고 수정하기가 가장 쉬운 것 같아요(awk를 모르는 경우)... 그런데, awk는 제가 배우고 싶은 언어 목록의 다음 언어입니다... ;)

관련 정보