如何在AWK中整理多个文件?

时间:2019-02-24 13:30:59

标签: bash csv awk

我正在尝试整理按日期命名的一系列.csv日志文件(例如2019-02-24.csv)。有很多,所以我正在尝试编写脚本。我制作了一个AWK脚本,它结合了单个文件:

awk ' FNR==1 { while (/"_time",PIN,FULLNAME,OFFICE,Acronym,Name/) getline; } 1 { print } ' 2019-01-01.csv >> usage_history.csv

但是当我尝试将AWK命令与BASH中的控制循环一起输入时,我失败了:

for i in {01..28}; do echo "awk ' FNR==1 { while (/\"_time\",PIN,FULLNAME,OFFCODE,Acronym,Name/) getline; } 1 { print } ' 2019-01-$i.csv >> user_history.csv"; done

当我运行此命令时,它会将正确的命令输出到命令行,但是awk脚本不会执行(它们只会被打印)。如果我在没有echo的情况下运行它,则会收到错误消息,告诉我该文件不存在;尽管所有文件都存在:

bash: awk ' FNR==1 { while (/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/) getline; } 1 { print } ' 2019-01-01.csv >> user_history.csv: No such file or directory

循环中我缺少什么?


以下是命令和错误消息的精简示例:

$ for i in {01..02}; do "awk ' FNR==1 { while (/\"_time\",PIN,FULLNAME,OFFCODE,Acronym,Name/) getline; } 1 { print } ' 2019-01-$i.csv >> user_history.csv"; done
bash: awk ' FNR==1 { while (/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/) getline; } 1 { print } ' 2019-01-01.csv >> user_history.csv: No such file or directory
bash: awk ' FNR==1 { while (/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/) getline; } 1 { print } ' 2019-01-02.csv >> user_history.csv: No such file or directory

3 个答案:

答案 0 :(得分:2)

尝试一下:

for i in {01..28}; do awk '!/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/' 2019-01-$i.csv >>user_history.csv;done

do之后的命令不应加引号。
而且您所做的基本上等于忽略标题行。
{print}之后的1是不必要的,单个1表示{print}1将提供true
-当只有一个表达式但没有任何块时,该块暗含{print}。
-只有一个正则表达式等于$0~/regex/,在这里我否定了它。

如果循环中没有其他命令,则可以使用一个awk命令来简化循环:

awk '!/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/' 2019-01-{01..28}.csv >>user_history.csv

但是,当其中一个文件不存在时,该文件将引发错误并停止执行。

另一种方法是:

awk '!/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/' 2019-01-[0-3][0-9].csv >>user_history.csv

此文件仅匹配文件名,而不是循环文件名。
它不会停止执行也不会引发错误,因此,如果缺少文件,您将不会知道。如果存在的话,它将匹配额外的文件。
例如,如果存在,它将读取2019-01-34.csv

因此,如果您想要警告(警告不会影响结果),但又不想停止命令,请使用第一个for循环。

陷阱:
[0-3][1-9]102030不匹配,但是会将3239匹配。
[0-9]*将匹配任何更长的数字,但20之前的293或类似的字符串顺序。

答案 1 :(得分:2)

请您尝试以下。

awk '!/"_time",PIN,FULLNAME,OFFCODE,Acronym,Name/' 2019-01-[0-9]*.csv >> user_history.csv

以下是要点 ,为什么可以使用这种方法:

1-使用for循环并调用awk命令,因为每次都过头了。当awk可以读取多个文件时,我们应该使用智能方法,然后我们应该起诉它。

2-现在出现了您在代码中尝试过的getline部分,因此,如果我们要取反任何字符串,则只需使用!/string_to_be_skipped/取反它,这样它将只查找那些没有此字符串。

3-在使用单个awk命令提及文件(多个文件)时,我使用了2019-01-[0-9]*.csv,原因是因为由于您没有告知是否每天创建文件,所以如果我们给它一个循环样式,并且该特定文件不存在,那么我们将收到错误消息。例如,假设我使用以下awk命令,其中有意删除了名为(2019-01-02.csv)的文件。

awk '........' 2019-01-{01..29}.csv
awk: cannot open 2019-01-02.csv (No such file or directory)

因此,为了避免此类情况,我使用了2019-01-[0-9]*.csv,其中它只会查找2019-01-0之后具有数字的文件,并且不会循环运行,并向我们抱怨某些xyz等文件丢失了。

答案 2 :(得分:1)

感谢@Tiw和@ RavinderSingh13的指导。这是适合我的最终awk脚本,在我的情况下,我每天都有多个天,几个月和几年的文件(在这种情况下,只有2018年和2019年):

  

awk'!/“ _ time”,PIN码,全名,OFFCODE,首字母缩写词,名称/'201 [8-9]-[0-1] [0-2]-[0-3] [0-9] .csv >> user_history.csv