FOO가 처음 나타나는 부분부터 시작하여 BAR이 처음 나타나는 부분까지 대용량 텍스트 파일의 일부를 추출하려면 어떻게 해야 합니까?
제 경우에는 mysqldump로 생성된 SQL 파일의 일부를 추출하려고 합니다.
답변1
크레딧@dgig그리고@파울로피드백을 도와준 사람!결정적인 perl
여기에 한 줄짜리 :
perl -lne 'if(/FOO/../BAR/){s/.*?(FOO)/$1/ if!$i++;s/BAR\K.*//&&print&&exit;print}' file
설명:
if(/FOO/../BAR/){ # perform the following actions on each line, starting
# with a line that contains FOO, and up to and including
# a line that contains BAR
s/.*?(FOO)/$1/ if!$i++; # only on the first line that contains FOO,
# delete all characters before FOO
s/BAR\K.*//&&print&&exit;# if the line contains BAR, remove characters
# after BAR, print the line and stop processing
print # simply print the line contents
이전 답변:
크레딧@파울로간단한 sed
해결책을 위해. 다음과 같이 간단하고 읽기 쉽습니다 awk
.
awk '/FOO/,/BAR/' file
하지만 너무 단순할 수 있습니다. 정확히 "FOO의 첫 번째 발생에서 시작하여 BAR의 첫 번째 발생에서 끝나는 텍스트 부분"이 아닌 전체 행을 반환합니다. 나는 이것이 FOO가 첫 번째 단어이고 BAR가 마지막 단어여야 한다는 것을 의미한다고 믿습니다. 정확히 그렇게 하려면 더 복잡한 대답이 필요합니다. 에서 그 일을 해보도록 하겠습니다 perl
.
간단한 경우(전체 줄 반환):
perl -lne 'print if /FOO/../BAR/' file
복잡한 경우(정확히 FOO에서 BAR까지):
perl -lne 'if(/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if!$i++;$_=~s/BAR\K.*//;print}' file
나는 범위 연산자에 변수를 할당하는 이와 동등한 솔루션을 좋아합니다.
perl -lne 'if($a=/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if$a==1;$_=~s/BAR\K.*// if$a=~/E/;print}' file
메모:추출할 텍스트의 한 부분만 있다고 가정합니다. 즉, FOO와 BAR로 구분된 첫 번째 단락 이후에 다른 FOO를 만나면 안 됩니다.
그렇지 않으면 간단한 사례는 이미 다음에서 더 이상 간단하지 않습니다 awk
.
awk '/FOO/,/BAR/ {print; if ($0~/BAR/) {exit} }' file
그리고 perl
:
perl -lne '(print&&/BAR/&&exit) if /FOO/../BAR/' file
복잡하고 더욱 세련된 솔루션은 다음과 같습니다.
perl -lne 'if(/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if!$i++;$_=~s/BAR\K.*//&&print&&exit;print}' file
그리고:
perl -lne 'if($a=/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if$a==1;$_=~s/BAR\K.*//&&print&&exit if$a=~/E/;print}' file
이 예는 문제에 조금 더 복잡함을 더해 한 줄짜리 문장이 유난히 명확하고 설명이 필요 없는 것에서 모호한 일련의 임의 문자처럼 보이는 것으로 어떻게 변하는지 보여줍니다. 필요할 때마다 추가 기능을 쉽게 추가하고 특수한 경우를 고려할 수 있는 독립형, 유지 관리 및 읽기 가능한 스크립트를 작성하는 것이 좋습니다.
답변2
이 경우에는 그렇게 어렵지 않을 것이라고 생각했습니다. 를 사용하면 sed
첫 번째 FOO 발생부터 첫 번째 BAR 발생까지(시도하지는 않았지만 아마도 두 번째 FOO에서 두 번째 BAR 같은 것이 더 어려울 것입니다.)
sed -nr '/FOO/ {
/FOO/ s/[^F]+FOO/FOO/p
:a
n
/BAR/ s/([^B]+BAR).*/\1/
p
/BAR/ q
ba
}' <<<'line1
> line2 FOO text1 FOO text2
> line3
> line4 BAR text3 BAR text4
> line5'
FOO text1 FOO text2
line3
line4 BAR