ライン範囲をライン範囲(sedまたはその他)に置き換える

ライン範囲をライン範囲(sedまたはその他)に置き換える

2つのテキストファイルがあります。両方ともfile1複数file2行があります。

$ 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

したがって、このコマンドを簡単に3回呼び出して一時ファイルに追加し、必要な場所にファイルを移動できます。すべて結合を使用してすべて結合し、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

それここで説明されています、唯一の違いは、特定のケースの1行の範囲です。

答え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

関連情報