Bash, Perl 및 Regex를 사용하여 텍스트 파일의 변수를 배열로 추출합니다.

Bash, Perl 및 Regex를 사용하여 텍스트 파일의 변수를 배열로 추출합니다.

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에 대한 전문가는 아니지만 sedPerl을 사용하면 다음과 같이 보일 것입니다.

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 정규식에 따라).

관련 정보