在shell中向现有数据添加列

时间:2019-03-17 04:25:44

标签: shell awk

我有一个带三个标头的csv。我想在其中添加一个额外的标头,称为“标签”。

$ cat TEST1/a.csv
    h1,h2,h3
    a,b,c
    d,e,f
$ awk '{print $0}' TEST1/a.csv
    h1,h2,h3
    a,b,c
    d,e,f
$ awk '{print $0, "tag"}' TEST1/a.csv
     tag2,h3
     tagc
     tagf

但是,如上所示,当前方法正在提供垃圾值。我如何获得如下所示的输出:-

h1,h2,h3,tag
a,b,c,TEST1/a.csv
d,e,f,TEST1/a.csv

最好在标签列中包含文件名。

2 个答案:

答案 0 :(得分:1)

我不确定您为什么会在第三个awk行中显示结果,我也不完全确定您要添加的最后一个字段是什么,因为您的“预期结果”不会与您提供的代码完全匹配。如果您的目标是在每行的最后一个字段中添加单词“ tag”,那么以下方法可能会起作用...

awk -F, '{$(NF+1)="tag"} 1' OFS=, TEST1/a.csv

这具有以下位:

  • -F,将字段分隔符设置为逗号,与CSV兼容。
  • $(NR+1)在每个记录的末尾添加一个新字段。
  • 1是“打印当前记录”的简写。
  • OFS=,将输出字段分隔符设置为逗号。

有几种方法可以构造相同的逻辑,并且所有方法都可以提供大致相同的结果。

这将在BEGIN块中设置输入和输出字段分隔符,并使用字段的添加作为打印行的条件。

awk 'BEGIN{FS=OFS=","} $(NF+1)="tag"' TEST1/a.csv

省去了记录的概念,只在每一行中添加了文本。

awk '{$0=$0 ",tag"} 1' TEST1/a.csv

通常,如果您要处理字段中的输入,我建议使用awk来理解这些字段,以防万一您将来需要操纵字段而不是流。如果需要流编辑器,可以使用sed

sed 's/$/,tag/' TEST1/a.csv
另一方面,

IF 您要在每行末尾添加文件名,并且仅在文本行中添加tag标头,您可能会执行以下操作:

awk 'NR==1 {$(NF+1)="tag"} NR>1 {$(NF+1)=FILENAME} 1' FS=, OFS=, TEST1/a.csv

这将生成您显示的结果,文件名位于最后一个字段中。当然,您可以根据数据的形状进行各种变化。如果要处理多个文件,每个文件的第一行都有标题,则可能需要这样做:

awk 'NR==1 {$(NF+1)="tag";print} FNR==1 {next} NR>1 {$(NF+1)=FILENAME} 1' FS=, OFS=, file1.csv file2.csv ...

此处的区别在于,在第一行上修改了标头并进行了打印,然后完全跳过了后续的第一行文件。

答案 1 :(得分:1)

通过查看OP的输出,我相信OP所需的是第一行,它需要将tag字符串添加到标题,其余各行应添加带有路径的文件名,如果是这种情况,请尝试以下。我还照顾了Input_file每行中的M \r个字符。

awk 'BEGIN{OFS=","} {gsub(/\r/,"")} FNR==1{print $0,"tag";next} {print $0,FILENAME}' TEST1/a.csv

输出如下。

h1,h2,h3,tag
a,b,c,TEST1/a.csv
d,e,f,TEST1/a.csv


如果要先删除Input_file中的M个控制字符,然后运行awk命令,然后使用以下命令。

tr -d '\r' '' < Input_file > temp_file  &&  mv temp_file Input_file

然后按照awk命令运行。

awk 'BEGIN{OFS=","}FNR==1{print $0,"tag";next} {print $0,FILENAME}' TEST1/a.csv