awk: 레이아웃 키워드를 사용하여 텍스트 파일 구문 분석

awk: 레이아웃 키워드를 사용하여 텍스트 파일 구문 분석

한 번에 한 줄씩 파일을 반복하고 일관된 출력을 생성하는 bash 스크립트를 만들고 싶습니다.

예.txt

ALBERT some a BRYAN some b CLAUDIA some c DAVID some d ERIK some e
ALBERT some a BRYAN some b ERIK some e
ALBERT some a BRYAN some b DAVID some d

몇 가지 참고사항:

  • 태그마다 단어 수가 다릅니다.
  • 키워드는 항상 같은 순서로 나타납니다.
  • 키워드의 전체 목록이 제공되며 시작하기 전에 지정할 수 있습니다.

원하는 출력:

some a; some b; some c; some d; some e
some a; some b;;; some e
some a; some b;; some d;

sed를 사용하면 키워드를 세미콜론으로 하나씩 쉽게 바꿀 수 있습니다.

sed -i 's/ALBERT/;/g' "example.txt"

특정 키워드가 누락된 경우 awk를 사용하여 각 줄을 반복하고 필요한 세미콜론을 추가하려면 어떻게 해야 합니까? 어떤 종류의 카운터가 도입되어야 한다고 생각합니까?

답변1

일부 태그("ALBERT"와 같은 이름)가 다른 행에서 누락된 것처럼 첫 번째 행에서 누락될 수 있다고 가정하면 2단계 접근 방식을 사용하여 먼저 모든 태그를 식별한 다음 모든 태그를 인쇄해야 합니다. 해당 줄에 표시되는지 여부에 관계없이 모든 줄에 적용되는 값입니다.

$ cat tst.awk
BEGIN { OFS=";" }
NR==FNR {
    for (i=1; i<NF; i+=3 ) {
        if ( !seen[$i]++ ) {
            tags[++numTags] = $i
        }
    }
    next
}
{
    delete tag2val
    for (i=1; i<NF; i+=3) {
        tag = $i
        val = $(i+1) FS $(i+2)
        tag2val[tag] = val
    }

    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        val = tag2val[tag]
        printf "%s%s", val, (tagNr<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk example.txt example.txt | column -t -s';' -o'; '
some a; some b; some c; some d; some e
some a; some b;       ;       ; some e
some a; some b;       ; some d;

위 코드는 모든 입력에 나타나는 순서대로 각 행의 모든 ​​레이블 값을 출력합니다.

라벨을 열 헤더로 처리하려면 다음을 수행하세요.

$ cat tst.awk
BEGIN { OFS=";" }
NR==FNR {
    for (i=1; i<NF; i+=3 ) {
        if ( !seen[$i]++ ) {
            tags[++numTags] = $i
        }
    }
    next
}
FNR==1 {
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        printf "%s%s", tag, (tagNr<numTags ? OFS : ORS)
    }
}
{
    delete tag2val
    for (i=1; i<NF; i+=3) {
        tag = $i
        val = $(i+1) FS $(i+2)
        tag2val[tag] = val
    }

    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        val = tag2val[tag]
        printf "%s%s", val, (tagNr<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk example.txt example.txt | column -t -s';' -o'; '
ALBERT; BRYAN ; CLAUDIA; DAVID ; ERIK
some a; some b; some c ; some d; some e
some a; some b;        ;       ; some e
some a; some b;        ; some d;

답변2

펄 사용:

#!/usr/bin/perl

# @keys is an array containing the keywords. It also determines
# the field output order.  This can be read from a file if needed,
# but here it's hard-coded.
my @keys = qw(ALBERT BRYAN CLAUDIA DAVID ERIK);

# create and pre-compile a regex matching all the keywords
my $keys = join("|",@keys);
my $keys_re = qr/$keys/;

# make an empty hash containing elements for all the keys so that
# we can start processing each input record afresh, with a fully
# populated list of keys.
my %empty = map +( $_ => '' ), @keys;


# main loop, process stdin and/or filename args
while(<>) {
  # clean up the input a little.
  chomp;            # trim newlines at EOL
  s/^\s*|\s*$//g;   # trim leading and trailing whitespace

  # ignore empty lines.
  next if (m/^$/);

  # NUL can't be in text input, so insert it as a marker around
  # the keywords. i.e. insert NULs before and after each keyword
  s/$keys_re/\000$&\000/g;

  # split the input record on NUL, trimming spaces and discarding
  # the first element (a bogus artificial field which only exists
  # as a side-effect of inserting a NUL before the first keyword.)
  my (undef,@record) = split /\s*\000\s*/;

  # pre-populate the fields hash for each record.
  my %fields = %empty;

  # now insert the real values for each keyword if they exist.
  foreach my $i (0..$#record) {
    $fields{$record[$i]} = $record[$i+1];
    $i++;
  };

  print join(";", map +( $fields{$_} ), @keys),"\n";
}

각 세미콜론 뒤에 공백을 추가하려면 print join(";",...)위 줄을 변경하고 추가하세요.

파일에서 키워드를 읽으려면 my @keys = qw(...)위 줄을 다음으로 바꾸세요.

# slurp in the keywords file and split it on any whitespace.
my @keys = split /\s+/, do {
  local $/;   # read entire file at once - slurp
  my $fname = 'keywords.txt';
  open(my $fh, '<', $fname) or die "Error opening $fname: $!";
  <$fh>
};

키워드.txt에는 공백, 탭, 줄 바꿈, CR/LF 등 수직 또는 수평 공백의 조합으로 구분된 키가 포함될 수 있습니다.

$ cat keywords.txt 
ALBERT
BRYAN   CLAUDIA
DAVID ERIK

예를 들어 로 저장 iterate.pl하고 실행 가능하게 만듭니다 chmod +x iterate.pl.

$ ./iterate.pl input.txt 
some a;some b;some c;some d;some e
some a;some b;;;some e
some a;some b;;some d;

더 적은 내용이나 다른 내용으로 더 예쁜 출력을 보려면 column를 사용할 수 있습니다.

$ ./iterate.pl input.txt | column -s';' -o'; ' -t
some a; some b; some c; some d; some e
some a; some b;       ;       ; some e
some a; some b;       ; some d; 

관련 정보