sed 또는 awk를 사용하여 텍스트 파일에서 CSV 생성

sed 또는 awk를 사용하여 텍스트 파일에서 CSV 생성

및 열이 포함된 CSV 파일을 생성 하고 싶습니다 name. 다음과 같이 보일 수 있습니다:foobar

name,foo,bar
a.txt,yes,no
b.txt,no,yes
c.txt,no,no

텍스트 파일이 포함된 디렉터리를 반복하고 해당 내용을 해석하면 CSV 파일이 생성됩니다.

a.txt의 내용은 다음과 같습니다.

foo:yes
bar:no
baz:?

b.txt의 내용은 다음과 같습니다.

foo:no
bar:yes

c.txt의 내용은 다음과 같습니다.

foo
bar:no
baz:yes

열이 없어야 합니다 baz. 지정된 foobar. 키-값 쌍도 누락되거나 불완전할 수 있습니다(c.txt에서처럼). 그렇다면 no가치 가 있어야합니다 .

or 을 사용 awk하면 가능하다고 확신 sed하지만 구현 방법을 모르겠습니다. 그것은 다음과 같습니다:

find . -name "*.txt" -print0 | xargs -0 -I {} sh -c "awk '...' {}"

답변1

해당 대상 키 중 하나 이상이 입력 파일에 존재하지 않는 경우에도 각 대상 키에 대한 열을 인쇄하려는 경우:

$ cat tst.awk
BEGIN {
    numKeys = split("foo bar", tmp)
    for (i in tmp) {
        keys[i] = tmp[i]
    }
    FS=":"; OFS=","
}
{ fnameKey2val[FILENAME,$1] = $2 }
END {
    printf "%s%s", "name", OFS
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s%s", key, (keyNr<numKeys ? OFS : ORS)
    }

    for (fileNr=1; fileNr<ARGC; fileNr++) {
        fname = ARGV[fileNr]
        printf "%s%s", fname, OFS
        for (keyNr=1; keyNr<=numKeys; keyNr++) {
            key = keys[keyNr]
            val = (fnameKey2val[fname,key] == "" ? "no" : fnameKey2val[fname,key])
            printf "%s%s", val, (keyNr<numKeys ? OFS : ORS)
        }
    }
}

또는 특정 키에 대한 열을 인쇄하고 싶지 않은 경우(해당 키가 모든 파일에 누락된 경우):

$ cat tst.awk
BEGIN {
    split("foo bar", tmp)
    for (i in tmp) {
        targets[tmp[i]]
    }
    FS=":"; OFS=","
}
!($1 in targets) { next }
!seen[$1]++ { keys[++numKeys] = $1 }
{ fnameKey2val[FILENAME,$1] = $2 }
END {
    printf "%s%s", "name", OFS
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s%s", key, (keyNr<numKeys ? OFS : ORS)
    }

    for (fileNr=1; fileNr<ARGC; fileNr++) {
        fname = ARGV[fileNr]
        printf "%s%s", fname, OFS
        for (keyNr=1; keyNr<=numKeys; keyNr++) {
            key = keys[keyNr]
            val = (fnameKey2val[fname,key] == "" ? "no" : fnameKey2val[fname,key])
            printf "%s%s", val, (keyNr<numKeys ? OFS : ORS)
        }
    }
}

둘 다 주어진 샘플 입력에서 동일한 출력을 생성합니다.

$ awk -f tst.awk *.txt
name,foo,bar
a.txt,yes,no
b.txt,no,yes
c.txt,no,no

답변2

또 다른 awk방법은 다음과 같습니다.

gawk -F':' -v OFS=',' '
BEGIN{ print "name", "foo", "bar"; };
    $2== ""    { $2="no"; };
    $1== "foo" { hold[FILENAME][1]= $2; };
    $1== "bar" { hold[FILENAME][2]= $2; };
END{ for (x in hold) print x, hold[x][1], hold[x][2]; }
' [abc].txt

산출:

name,foo,bar
c.txt,no,no
a.txt,yes,no
b.txt,no,yes

답변3

진주 방법:

perl -lne '
  BEGIN {
    @A = qw(foo bar);
    @{$h{$_}}{@A} = qw(no) x @A for @ARGV;
  }
  /^(foo|bar)(:.*|$)/ and 
    ($h{$ARGV}{$1} = length($2)<2?"no":$2) =~ s/^://;
  }{$,=",";
  print q(name), @A;
  print $_, @{$h{$_}}{@A} for sort keys %h;
' -- *.txt
name,foo,bar
a.txt,yes,no
b.txt,no,yes
c.txt,no,no

또 다른 접근 방식은 grep-sort-sed 파이프라인을 사용하고 파일에 foo/bar가 있다고 가정합니다.

echo 'name,foo, bar'
grep -HE '^(foo|bar)(:|$)' *.txt |
sed -e '/:.*:/!s/$/:no/' |
sort -t: -k1,1 -k2,2r |
sed -Ee 'N;s/\n[^:]+:/:/;y/:/,/' |
cut -d, -f1,3,5

관련 정보