そして列を含むCSVファイルを生成したいと思いますname
。次のように見えます。foo
bar
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
。指定foo
およびbar
。キーと値のペアも欠けているか不完全になる可能性があります(c.txtのように)。もしそうなら、no
価値があるはずです。
orを使うawk
と可能だと確信していますsed
が、実装方法がわかりません。それは次のとおりです。
find . -name "*.txt" -print0 | xargs -0 -I {} sh -c "awk '...' {}"
答え1
そのターゲットキーの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