문제를 설명하기 위해 예를 들어보세요. 파일이 있어요
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