
Bash, Perl 및 Regex를 사용하여 텍스트 파일에서 변수를 추출하고 싶습니다.
파일은 다음과 같습니다($str 변수가 읽혀졌습니다).
Filename: XXXXX
Type: XXX
Size: XXXX
Unimportant thing: XXXX
Filename: YYYYY
Type: YYY
Size: YYYY
Unimportant thing: YYYY
각 청크의 파일 이름, 유형 및 크기가 필요합니다. 배열이 가장 좋지만 주어진 문자로 구분된 이러한 변수를 포함하는 문자열도 허용됩니다.
그러나 일부 필드(예: 크기 또는 유형)가 누락되는 경우도 있습니다. 이 레코드를 생략하고 싶기 때문에 여러 줄에 걸쳐 일치할 수 있는 정규식이 필요한 것 같습니다.
나는 다음을 시도했다:
perl -pe 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
하지만 이는 수정 없이 원본 텍스트를 인쇄합니다.
그런 다음 p 명령줄 인수 없이 시도했습니다(줄을 반복하는 대신 이 방법으로 전체 파일을 처리하고 싶었습니다).
perl -e 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
이것은 아무것도 인쇄하지 않습니다(빈 결과).
그런 다음 -p를 제거하면 Perl이 결과가 인쇄되기를 원한다는 사실을 알지 못할 수도 있다고 생각했기 때문에 정규식 앞에 인쇄를 추가하려고 시도했습니다.
perl -e 'print s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
여전히 성공하지 못했습니다(빈 결과).
내가 무엇을 놓치고 있나요?
고쳐 쓰다:
나는 이것을 한 줄의 Perl 명령으로 원합니다.
답변1
내 Perl 지식은 약하지만 Perl에 대한 답을 아는 사람이 없기 때문에 시도해 보겠습니다.
데이터를 파일로 전달하면 한 줄에 세 개의 값이 탭으로 구분된 줄로 인쇄됩니다.
perl -e 'while (<>) { $s .= $_; } chomp $s; @arr = split(/\n{2,}/, $s); foreach my $a(@arr) { $a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next; print "$a"; } ' infile
결과:
XXXXX XXX XXXX
YYYYY YYY YYYY
이는 다소 무차별적인 방법이지만 입력을 단락/블록으로 분할한 다음 각 단락/블록에 여러 줄 정규 표현식을 적용하는 방식으로 작동합니다.
세부 사항...
while (<>) { $s .= $_; }
- 입력을 단일 문자열로 변환합니다.chomp $s
- 문자열에서 후행 개행 문자를 제거합니다.@arr = split(/\n{2,}/, $s)
- 연속된 개행에서 문자열을 분할합니다. 이렇게 하면 단락/블록으로 나뉩니다. 청크를 배열에 저장합니다.foreach my $a(@arr)
- 각 배열 요소(블록)를 반복합니다. 다음 두 줄의 코드가 각 블록에 적용됩니다.$a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next
- 관심 있는 3개 분야에서 값을 추출합니다. 대체가 발생하지 않으면(예를 들어 값이 누락되어 정규 표현식이 일치하지 않음을 의미) 이 블록을 건너뛰고 다음 블록으로 이동합니다.print "$a"
- 대체 결과를 인쇄합니다: 탭으로 구분된 세 개의 값.
그런데 저는 Perl을 그렇게 많이 사용하지 않기 때문에 이보다 더 우아한 솔루션이 있을 수 있습니다.
답변2
Perl에 대한 전문가는 아니지만 sed
Perl을 사용하면 다음과 같이 보일 것입니다.
sed -n '/^$/d;/^Filename/,/^Unimportant/{:a;/Unimportant/!{N;ba};s/Filename: \([^\n]*\)\nType: \([^\n]*\)\nSize: \([^\n]*\)\n.*/\1\t\2\t\3/p};'
어디:
/^$/d
-- 빈 줄을 모두 제거합니다./^Filename/,/^Unimportant/
Filename부터 Unimportant까지의 각 블록은 개별적으로 일치됩니다. 각 블록에 중요하지 않은 기록이 있다고 가정합니다.:a;/Unimportant/!{N;ba};
전체 블록을 버퍼로 연결합니다.sed
여러 줄 정규식을 사용하거나 한 번에 여러 줄을 처리할 수 있는 방법이 없기 때문에 필요합니다 .s/Filename: \([^\n]*\)\nType: \([^\n]*\)\nSize: \([^\n]*\)\n.*/\1\t\2\t\3/p};
필요한 형식으로 바꾸십시오(Perl 정규식에 따라).