使用来自多个输入文件的字符串作为使用AWK的CSV文件中选择列的搜索条件

时间:2015-07-07 02:09:02

标签: bash shell csv awk

问题的本质:

我有一个包含10列的CSV文件,其中4列指定疾病代码。让我们说这些是第1列。我有2个文本文件包含"包含"和"排除"码。

包含文件如下:带有n个输入字符串的文件,每个文件都在换行符

示例:

123
12300
12301
124
12400
12401
1250

排除文件如下:一个带有m输入字符串的文件,每个文件都在换行符上。

示例:

456
457
458
459

CSV文件的截断版本如下所示:

D1,D2,D3,D4,A,B,C,D,E,F
123,00,145,567,A1,B1,C1,D1,E1,F1
890,001,456,0009,A2,B2,C2,D2,E2,F2
12301,456,00,145,A3,B3,C3,D3,E3,F3
567,1250,010,321,A4,B4,C4,D4,E4,F4

使用AWK,如何获取名为inclusionexclusion的2个文件以及返回以下内容的CSV文件:

D1,D2,D3,D4,A,B,C,D,E,F
123,00,145,567,A1,B1,C1,D1,E1,F1
567,1250,010,321,A4,B4,C4,D4,E4,F4

CSV文件可以有数百万行,而inclusionexclusion文件可以包含数十行。这不是家庭作业,我很感激帮助。

1 个答案:

答案 0 :(得分:3)

使用grep

$ head -n1 <file; grep -E "(^|,)($(tr '\n' '|' <inclusion))(,|$)" file | grep -Ev "(^|,)($(tr '\n' '|' <exclusion))(,|$)"
D1,D2,D3,D4,A,B,C,D,E,F
123,00,145,567,A1,B1,C1,D1,E1,F1
567,1250,010,321,A4,B4,C4,D4,E4,F4

使用awk

$ awk -v inc="(^|,)($(tr '\n' '|' <inclusion))(,|$)" -v exc="(^|,)($(tr '\n' '|' <exclusion))(,|$)" 'NR==1 || ($0 ~ inc && ! ($0 ~ exc))' file
D1,D2,D3,D4,A,B,C,D,E,F
123,00,145,567,A1,B1,C1,D1,E1,F1
567,1250,010,321,A4,B4,C4,D4,E4,F4

如何运作

对于grep和awk解决方案,关键步骤是创建与包含或排除文件匹配的正则表达式。因为它较短,所以我们以exclusion为例。我们可以为它创建一个正则表达式,如下所示:

$ echo "(^|,)($(tr '\n' '|' <exclusion))(,|$)"
(^|,)(456|457|458|459|)(,|$)

inclusion的正则表达式类似。一旦创建了包含和排除正则表达式,我们就可以使用grep或awk。如果使用awk,我们使用条件:

NR==1 || ($0 ~ inc && ! ($0 ~ exc))

如果此条件为真,则awk执行默认操作,即打印该行。如果(1)我们位于第一行,NR==1或者(2)该行匹配正则表达式inc,并且与排除的正则表达式不匹配,则条件为真,{ {1}}。

替代awk解决方案

exc

通过多行写出的相同代码如下:

$ gawk -F, -v inc="$(<inclusion)" -v exc="$(<exclusion)" 'BEGIN{n=split(inc,x,"\n"); for (j=1;j<=n;j++)incl[x[j]]=1; n=split(exc,x,"\n"); for (j=1;j<=n;j++)excl[x[j]]=1;} NR==1{print;next} {p=0;for (j=1;j<=NF;j++) if ($j in incl)p=1; for (j=1;j<=NF;j++) if ($j in excl) p=0;} p' file
D1,D2,D3,D4,A,B,C,D,E,F
123,00,145,567,A1,B1,C1,D1,E1,F1
567,1250,010,321,A4,B4,C4,D4,E4,F4

以上内容会创建包含gawk -F, -v inc="$(<inclusion)" -v exc="$(<exclusion)" ' BEGIN{ n=split(inc,x,"\n") for (j=1;j<=n;j++)incl[x[j]]=1 n=split(exc,x,"\n") for (j=1;j<=n;j++)excl[x[j]]=1 } NR==1{ print next } { p=0 for (j=1;j<=NF;j++) if ($j in incl) p=1 for (j=1;j<=NF;j++) if ($j in excl) p=0 } p ' file incl数据的数组exclinclusionexclusion中包含字段的所有行都会标记为打印incl。但是,如果该行包含p=1中的字段,则excl设置为false p