我是另一个编写脚本的新手(刚刚发现了,这让我大吃一惊!)我想要做的是有一个脚本,将大量的.csv文件编译成一个bigfile.csv,移除头,并插入我自己的头。我发现了以下解决方案:
awk 'FNR > 1' *.csv > bigfile.csv
sed -i 1i"Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..." bigfile.csv太棒了!但是,当我尝试使用这个文件进行分析时,我会因为行差而得到错误。我看了一下,确实,里面有一些疯狂的条目。
幸运的是,我希望从原始.csv文件中得到的每一行都有第一列"MD“条目。那么,有谁知道我如何告诉awk只从第一个单元格中包含"MD“的.csv文件中取线?
编辑:谢谢你的帮助,伙计们,这很有魅力!不幸的是,里面还有一些奇怪的数据
CParserError: Error tokenizing data. C error: Expected 51 fields in line 6589, saw 54有一个简单的调整,是否有办法再次只采取线与51个字段?
发布于 2016-07-14 12:05:55
我将在这里讨论一下,假设您在sed中添加的行实际上是您要去掉的标题。
如果是这样的话,我建议您跳过sed行,然后告诉awk删除不是第一行的文件的第一行。
接下来,如果只想在第一个字段中包含文本MD的行,可以使用简单的regex进行测试。
awk -F, '
FNR==1 && NR > 1 { next } # skip the header on all but the first file
NF != 51 { next } # skip this line if field count is wrong
$1 ~ /MD/ # print the line if the first field matches
' *.csv > /path/to/outputfile.csv-F,选项告诉awk使用逗号分隔字段。NR是处理的记录总数,而FNR是当前文件中的当前记录号。print为命令(打印当前行)。当然,如果您愿意,可以将整个awk脚本放在一行上。为了便于阅读,我把它分开了。
如果您的outputfile.csv位于获取输入csv文件的"glob“目录中,那么请注意,新文件将由shell创建,而不是由awk创建,并且也可能作为输入文件处理。如果您计划使用>>将重定向附加到现有文件,这可能会引起关注。
更新
正如您已经提到的,您要添加的头与您去掉的标头不同,通过将awk脚本更改为如下所示,您仍然可以避免使用sed这样的单独命令:
awk -F, '
BEGIN {
print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."
}
FNR==1 { next } # skip the header on all files
NF != 51 { next } # skip this line if field count is wrong
$1 ~ /MD/ # print the line if the first field matches
' *.csv > /path/to/outputfile.csv在处理任何输入行之前,将执行awk的BEGIN块中的命令,因此,如果在那里打印新的标题,它们将出现在(重定向)输出的开头。(请注意,如果要在所有输入处理后生成脚注/汇总/etc,则存在类似的END块。)
发布于 2016-07-14 11:54:57
awk 'BEGIN{print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
if(FNR > 1){print}' *.csv > bigfile.csvFNR在每个文件之后重置那个awk进程,但是NR不和NR=FNR只用于第一个文件。
一个小插图(当然是用我的测试数据)
$ cat f1
Name,Roll
A,10
B,5
5$ cat f2
Name,Roll
C,56
D,44
$ awk 'BEGIN{print "Naam,RollNo"}FNR > 1{print}' f*>final
$ cat final
Naam,RollNo
A,10
B,5
C,56
D,44Note
正如您所看到的,最后一个文件的新头被转到awk BEGIN部分,该部分在开始时才被执行。
来到您的目标
我想要的原始.csv文件中的每一行都有第一列"MD“项
awk 'BEGIN{FS=",";print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
if(FNR > 1 && $1 == "MD" && NF == 51){print}' *.csv > bigfile.csvNotes
这一条与第一种一般情况没有什么区别。
,作为现场分选器。FNR > 1 && $1 == "MD"的意思是,只有当第一个字段是MD($1 == "MD")且字段数为51(NF == 51)时,我才不想要标题(FNR=1)和打印内容。惯用方式
正如[ @ghoti ]在他的评论中提到的:
awk的“默认”命令已经是
{print}
因此,上面的脚本可以重写为:
awk 'BEGIN{FS=",";print "Ident - MD,Node ID,Date,Time,Sub Seq#,NO2..."}
(FNR > 1 && NF == 51 && $1 == "MD")' *.csv > bigfile.csv发布于 2016-07-14 11:57:41
一条花哨的单线邮轮会想:-
awk -F',' 'NR > 1 && $1 ~ /^MD/ && NF == 51 { print }' *.csv > /someotherpath/bigfile.csv使用完整的bash脚本的适当方法应该是类似于类似的东西,而不是花哨的一行:-
#!/bin/bash
# Am assuming the the '.csv' files are a single ',' separated
for i in *.csv; do
[ -e "$i" ] || continue # To handle when no input *.csv files present
awk -F',' 'NR > 1 && $1 ~ /^MD/ && NF == 51 { print }' "$i" > /someotherpath/bigfile.csv
done解决方案的关键是使用awk的NR & NF变量,该变量跟踪行内的当前行和nth字段,因此理想情况下,NR > 1将跳过正在处理的标题部分,$1 ~ /^MD/只返回第一列以模式开头的行,NF ==51打印包含51个字段的行。
https://stackoverflow.com/questions/38373385
复制相似问题