
다음과 같은 파일이 있습니다.
블라 블라
패턴 2
블라
패턴 1
패턴 2
블라
블라 패턴 1 블라
블라
패턴 1
pattern1
마지막 일치 항목 이후 첫 번째 항목이 포함된 전체 굵은 줄을 제거하고 싶습니다 pattern2
.
누구든지 아이디어가 있나요?
감사해요!
답변1
이것은 하나의 ex
라이너입니다. ( ex
전작과 스크립트 형식에서는 그렇습니다 vi
.)
printf '%s\n' '$?pattern2?/pattern1/d' x | ex file.txt
저장 x
및 종료. %p
변경된 파일만 인쇄하고 싶다면 다음으로 변경하세요.아니요변경 사항을 저장합니다(테스트용으로 좋음).
$
는 파일의 마지막 라인을 나타내며, 는 현재 위치에서 시작하여 ?pattern2?
역방향 검색의 첫 번째 결과를 나타내는 주소이고, 은 라인 삭제 명령입니다.pattern2
/pattern1/
d
ex
정방향 및 역방향 주소 지정이 필요할 때 사용합니다.
vi
Vim에서도 동일한 작업을 대화식으로 수행할 수 있습니다.
vim file.txt
그런 다음 입력하십시오.
:$?pattern2?/pattern1/d
그리고 Enter를 누르세요.
그런 다음 저장하고 :x
Enter를 눌러 종료하십시오.
답변2
여기에는 무차별적인 접근 방식이 있습니다. 데이터를 읽고 두 번 반복합니다. 첫 번째는 패턴 2의 마지막 발생을 검색하고, 두 번째는 패턴 1의 첫 번째 발생을 검색합니다.
#!/usr/bin/perl
# usage: perl remove-pattern.pl [file]
use strict;
# reads the contents of the text file completely
# removes end of line character and spurious control-M's
sub load {
my $file = shift;
open my $in, "<", $file or die "unable to open $file : $!";
my @file_contents = <$in>;
foreach ( @file_contents ) {
chomp;
s/\cM//g;
}
return @file_contents;
}
# gets the first file from the command line
# after the perl script
my $ifile = shift;
# read the text file
my @file_contents = &load($ifile);
# set 2 variables for the index into the array
my $p2 = -1;
my $p1 = -1;
# loop through the file contents and find the last
# of pattern2 (could go reverse the data and find the
# first of pattern2
for( my $i = 0;$i < @file_contents; ++$i ) {
if( $file_contents[$i] =~ /pattern2/) {
$p2 = $i
}
}
# start at the location of the last of pattern2
# and find the first of pattern1
for( my $i = $p2; $i < @file_contents; ++$i ) {
if($file_contents[$i] =~ /pattern1/) {
$p1 = $i ;
last;
}
}
# create an output file name
my $ofile = $ifile . ".filtered";
# open the output file for writing
open my $out, ">", $ofile or die "unable to open $ofile : $!";
# loop through the file contents and don't print the index if it matches
# p1. print all others
for( my $i = 0;$i < @file_contents; ++$i ) {
print $out "$file_contents[$i]\n" if ($i != $p1);
}
--- data.txt ---
bla bla
pattern2
bla
pattern1
pattern2
bla
bla pattern1 bla
bla
pattern1
위의 Perl 스크립트 이름이 "remove-pattern.pl"인 경우 data.txt 입력 파일이 주어지면 다음 명령을 사용하여 실행됩니다. %> perl delete-pattern.pl data.txt
생성된 출력 파일 "data.txt.filtered"
--- data.txt.filtered ---
bla bla
pattern2
bla
pattern1
pattern2
bla
bla
pattern1
답변3
줄의 줄 번호를 찾으려면 다음을 수행하십시오.
lineno=$( nl file | tac | awk '/pattern1/ {last = $1} /pattern2/ {print last; exit}' )
nl
파일에 줄 번호를 추가하고,
tac
줄을 뒤집고
, awk
줄 번호를 인쇄하는 데 사용됩니다.마지막"모드 1"앞으로이것첫 번째"모드 2".
그런 다음 이 줄을 삭제하세요.
sed -i "${lineno}d" file
답변4
파일을 한 번만 전달하고 메모리에 있는 줄 수를 최소화하려는 경우 awk
상태 시스템 접근 방식을 사용할 수 있습니다. 이는 가장 짧은 솔루션은 아니지만 쉽게 찾아내고 읽고 유지 관리할 수 있습니다. 상태 이름을 숫자로 대체하여 (잠재적으로) 더 효율적으로 만들 수 있습니다.
PATTERN1=pattern1 PATTERN2=pattern2 awk '
BEGIN {
p1 = ENVIRON["PATTERN1"]
p2 = ENVIRON["PATTERN2"]
state = "init"
}
state == "init" {
if ($0 ~ p2) state = "p2_found"
print
next
}
state == "p2_found" {
if ($0 ~ p1) {
state = "p1_found"
p1_line = $0
printf "%s", hold
hold = ""
} else if ($0 ~ p2) {
# we can print the text held since the last p2
printf "%s", hold
hold = $0 RS
} else hold = hold $0 RS
next
}
state == "p1_found" {
if ($0 ~ p2) {
state = "p2_found"
# the line that matched p1 is not discarded
printf "%s\n%s", p1_line, hold;
hold = ""
}
hold = hold $0 RS
}
END {
# here we are not printing p1_line which is how it is discarded
printf "%s", hold
}'
pattern1
( sum과 일치하는 행이 없다고 가정합니다 pattern2
.)