패턴 일치 후 행을 쉘의 다른 위치(다른 일치 직전)로 이동하십시오.

패턴 일치 후 행을 쉘의 다른 위치(다른 일치 직전)로 이동하십시오.

문제를 설명하기 위해 예를 들어보세요. 파일이 있어요

AAA

BBB

CCC

DDD

EEE

FFF

ABAB

ACAC

GGG

HHH

경기 후 2줄을 이동하고 싶습니다.아바부도착 전DDD. 따라서 수정된 파일은 다음과 같습니다.

AAA

BBB

CCC

ABAB

ACAC

DDD

EEE

FFF

GGG

HHH

이를 처리할 수 있는 멋진 방법을 찾고 있으며, 가급적 sed를 사용하는 것이 좋습니다.

답변1

참고: 귀하의 데이터가 그렇다고 가정합니다.아니요각 항목 사이에 빈 줄이 있으면 4줄 문제를 해결해야 합니다 +.+3

GNU 사용 ed:

$ ed -s file <<EOF
/ABAB/,//+m?DDD?-
,p
q
EOF

어디

  • /ABAB/,//+/ABAB/일련의 줄과 이전 일치 항목의 //한 줄을 처리합니다.
  • m지정된 행을 다음으로 이동합니다.
  • ?DDD?-이전 행과 일치하고 DDD한 행을 뺍니다.
  • ,p전체 버퍼를 인쇄합니다.

한 줄로,

printf '/ABAB/,//+m?DDD?-\n,p\nq\n' | ed -s file

file자리에서 편집 하려면 ,p\nq\n(,wq\n의식과그것).

답변2

원하므로 sed다음과 같이 할 수 있습니다.

sed -e '
    /DDD/,/ABAB/! b
    H;/ABAB/!{$!d;};g
    s/\(\n.*\)\n\(.*\)/\2\1/
' input.txt

편집자에게는 이것이 간단합니다 ed.

 ed -s input.file -  <<\eof
 /ABAB/m?DDD?-
 wq
 eof

답변3

Python(단일 읽기)

파일을 읽고 두 패턴 사이의 내용을 저장하는 작업은 다음과 같이 수행할 수 있습니다.

#!/usr/bin/env python3
import sys

flag=False
vals = []
with open(sys.argv[1]) as fd:
    for line in fd: 
        if line.strip() == "DDD" or flag:
            # encountered line where we should stop appending values
            if line.strip() == "ABAB": 
                flag = False
                # print the line and two others, then move in what was between originally
                print(line.strip())
                for i in range(2):
                    print(fd.readline().strip())
                print("\n".join(vals))
                continue
            # store values while we haven't hit ABAB
            flag = True
            vals.append(line.strip())
            continue

        print(line.strip())

Python(이중 읽기)

파일을 두 번 읽어야 했던 원래 awk 아이디어를 재사용하면 Python에서도 동일한 작업을 수행할 수 있습니다.

#!/usr/bin/env python3
import sys


flag_pos,match = 0,0
vals = []
with open(sys.argv[1]) as fd:
     for index, line in enumerate(fd):
         if line.strip() == "DDD":
             flag_pos = index
         if line.strip() == "ABAB":
             vals.append(line.strip())
             fd.readline()
             vals.append(fd.readline().strip())


with open(sys.argv[1]) as fd:
    for index,line in enumerate(fd):
        if index == flag_pos:
            print("\n\n".join(vals),"\n")
        if line.strip() in vals:
            fd.readline()
            continue
        print(line.strip()) 

스크립트는 다음과 같이 저장하고 다음 movelines.py과 같이 호출 할 수 있습니다../movelines.py input.txt

AWK

이는 gawk다음보다 구현하기가 더 쉬울 수 있습니다 sed.

$ awk 'NR==FNR && $0=="ABAB" { a[i++]=$0;getline;getline; a[i++]=$0; }; NR!=FNR { if($0=="DDD") for(val in a) printf "%s\n\n",a[val];  if($0 == "ABAB") {getline;getline;getline;} print $0   }' input.txt input.txt
AAA

BBB

CCC

ABAB

ACAC

DDD

EEE

FFF


GGG

HHH

여기서 비결은 파일을 awk두 번 전달하여 이동하려는 줄을 찾은 첫 번째 읽기와 실제로 이동한 두 번째 읽기를 구별하고 읽는 것입니다.

제공한 예제와 같이 실제 파일에 빈 줄이 없으면 getline두 개의 빈 줄 대신 하나만 필요하며 "%s\n"코드의 두 번째 부분에서는 충분합니다.

더 쉽게 읽을 수 있도록 다음은 주석이 포함된 여러 줄 버전의 코드입니다.

# on first reading NR != FNR, 
# so lets store ABAB and the other line into array
awk 'NR==FNR && $0=="ABAB" { 
        # i variable will be initialized once incremented first time
        a[i++]=$0;getline;getline; a[i++]=$0; 
    };
    # Here we are reading the same file second time 
    NR!=FNR { 

        if($0=="DDD") 
            for(val in a) 
                printf "%s\n\n",a[val]; 
        # Skip what we matched already
        if ($0 == "ABAB"){
            getline;
            getline;
            getline;
        }
        print $0   
     }' input.txt input.txt

답변4

나는 다음 방법으로 그것을했다

주문하다

Step1: h=`sed -n '/[A-Za-z]\{4\}/p' filename| sed -n '1p'`
step2:m=`sed -n '/[A-Za-z]\{4\}/p' filename| sed -n '2p'`
step3

    sed '/[A-Z]\{4\}/d' filename|sed "/CCC/s/.*/&\n\n$h\n\n$m/g"| sed '/^$/d' 

산출

AAA
BBB
CCC
ABAB
ACAC
DDD
EEE
FFF
GGG
HHH

관련 정보