라인 범위를 라인 범위(sed 또는 기타)로 교체

라인 범위를 라인 범위(sed 또는 기타)로 교체

두 개의 텍스트 파일이 있습니다: file1file2둘 다 여러 줄이 있습니다.

$ cat file1
line one
line two
line three
line four
line five

$ cat file2
line A
line B
line C
line D
line E
line F

하나 교체하고 싶어요범위라인 file1(라인에서 1_start라인으로 1_end), 여기서범위라인 file2(라인에서 2_start라인으로 2_end).

예를 들어, 2,4in 의 행을 from 의 행 file1으로 바꿉니다 .3,5file2

지금까지 내가 할 수 있었던 유일한 file2일은

$ sed -n 3,5p file2

그러나 그것은 그들을 거기로 데려가는 데 도움이 되지 않습니다 file1. 가능합니까 sed? 그렇지 않은 경우 유사한 도구를 사용할 수 있습니까?

답변1

sed주어진 행 범위는 다음과 같이 인쇄될 수 있습니다:

sed -n 'X,Yp' filename

여기서 X는 범위의 첫 번째 행이고 Y는 마지막 행입니다. 명시적으로 지시하지 않는 한 아무것도 인쇄하지 말라고 -n지시합니다 . 이는 아래 범위에서 수행하는 작업입니다.sedp

따라서 이 명령을 쉽게 세 번 호출하고 임시 파일에 추가한 다음 원하는 위치로 파일을 이동할 수 있습니다. 모두 결합을 사용하여 모두 결합 cat하고 모두 결합 할 수도 있습니다.프로세스 교체이 예에 표시된 대로(나는 방금 허공에서 가져온 줄 번호를 사용하고 있습니다. $이는 파일의 마지막 줄입니다):

cat <(sed -n '1,5p' file1) <(sed -n '10,12p' file2) <(sed -n '9,$p' file1) > file1.tmp && mv file1.tmp file1

file1여기서는 6, 7, 8행을 10, 11, 12행으로 바꿉니다 file2.

고쳐 쓰다:@MiniMax님 감사합니다지적cat다음을 수행하면 이러한 상황과 프로세스 교체를 피할 수 있습니다.

{ sed -n '1,5p' file1; sed -n '10,12p' file2; sed -n '9,$p' file1; } > file1.tmp && mv file1.tmp file1

결국 키스하세요. :)

답변2

또 다른 방법 은 명령을 sed사용하는 것인데 , 내부 옵션도 사용해야 하는 경우 편리합니다.r-i

$ sed -n '3,5p; 5q;' f2 | sed -e '2r /dev/stdin' -e '2,4d' f1
line one
line C
line D
line E
line five

$ # if /dev/stdin is not supported
$ sed -n '3,5p; 5q;' f2 > t1
$ sed -e '2r t1' -e '2,4d' f1

알림을 주신 don_crissti에게 감사드립니다. 파일 2에서 필요한 줄이 있으면 종료할 수 있습니다.

답변3

대용량 입력 파일의 경우 이 방법이 더 빠를 수 있습니다.

# replacing lines m1,m2 from file1 with lines n1,n2 from file2
m1=2; m2=4; n1=3;
{ head -n $((m1-1)); { head -n $((n1-1)) >/dev/null; head -n $((n2-n1+1));
} <file2; head -n $((m2-m1+1)) >/dev/null; cat; } <file1

그것은여기에 설명되어 있습니다, 유일한 차이점은 특정 경우의 한 줄 범위입니다.

답변4

저는 최근에 Python으로 모든 작업을 시작했습니다. 따라서 원하는 작업을 수행할 Python 프로그램은 다음과 같습니다.

#!/usr/bin/env python2
# -*- coding: ascii  -*-
"""replace_range.py"""

import sys
import argparse

parser = argparse.ArgumentParser()

parser.add_argument(
    "matchfile",
    help="File in which to replace lines",
)
parser.add_argument(
    "matchrange",
    help="Comma-separated range of Lines to match and replace",
)
parser.add_argument(
    "replacementfile",
    help="File from which to get replacement lines"
)
parser.add_argument(
    "replacementrange",
    help="Comma-separated range of lines from which to get replacement"
)

if __name__=="__main__":

    # Parse the command-line arguments
    args = parser.parse_args()

    # Open the files
    with \
    open(args.matchfile, 'r') as matchfile, \
    open(args.replacementfile, 'r') as replacementfile:

        # Get the input from the match file as a list of strings 
        matchlines = matchfile.readlines()

        # Get the match range (NOTE: shitf by -1 to convert to zero-indexed list)
        mstart = int(args.matchrange.strip().split(',')[0]) - 1
        mend = int(args.matchrange.strip().split(',')[1]) - 1

        # Get the input from the replacement file as a list of strings 
        replacementlines = replacementfile.readlines()

        # Get the replacement range (NOTE: shitf by -1 to convert to zero-indexed list)
        rstart = int(args.replacementrange.strip().split(',')[0]) -1
        rend = int(args.replacementrange.strip().split(',')[1]) - 1

        # Replace the match text with the replacement text
        outputlines = matchlines[0:mstart] + replacementlines[rstart:rend+1] + matchlines[mend+1:]

        # Output the result
        sys.stdout.write(''.join(outputlines))

실제 모습은 다음과 같습니다.

user@host:~$ python replace_range.py file1 2,3 file2 2,4

line one
line B
line C
line D
line four
line five

관련 정보