【问题标题】:prefix every header column with string using awk使用 awk 为每个标题列添加字符串前缀
【发布时间】:2021-10-20 03:28:59
【问题描述】:

我有一堆大的 csv 我想用固定字符串作为每个标题列的前缀。每个文件有 500 多列。

假设我的标题是:

number;date;customer;key;amount

我试过这条 awk 行:

awk -F';' 'NR==1{gsub(/[^a-z_]/,"input_file.")} { print }'

但我明白了(注意第一列缺少前缀并且分隔符被删除):

numberinput_file.dateinput_file.customerinput_file.keyinput_file.amount

预期输出:

input_file.number;input_file.date;input_file.customer;input_file.key;input_file.amount

【问题讨论】:

    标签: csv awk


    【解决方案1】:

    您的 gsub 会用前缀粗暴地替换输入中任何位置的任何非字母字符 - 包括您的列分隔符。

    print 可以在脚本的最后缩写为常用成语1;这只是意味着“此条件为真;对每一行执行默认操作(即全部打印)”尽管这只是一种风格上的改变。

    awk -F';' 'NR==1{
        sub(/^/, "input_file."); gsub(/;/, ";input_file."); }
      1' filename
    

    如果您想对多个文件执行此操作,可能会在其周围放置一个 shell 循环。如果您只想将所有内容连接到标准输出,则可以一次性将所有文件提供给 Awk(在这种情况下,您可能不想在第一个文件之后打印任何文件的标题行;也许更改 1NR==1 || FNR != 1)。

    【讨论】:

    • 不,在这种情况下,设置 FS/OFS 没有任何区别......这相当于 sed '1 s/[^;]*/input_file.&/g'
    【解决方案2】:

    我会按照下面的方式使用 GNU AWK,让 file.txt 内容成为

    number;date;customer;key;amount
    1;2;3;4;5
    6;7;8;9;10
    

    然后

    awk 'BEGIN{FS=";";OFS=";input_file."}NR==1{$1="input_file." $1}{print}' file.txt
    

    输出

    input_file.number;input_file.date;input_file.customer;input_file.key;input_file.amount
    1;2;3;4;5
    6;7;8;9;10
    

    说明:我将OFS 设置为;,后跟前缀。然后在第一行中,我向第一列添加前缀,这会触发字符串重建。在任何其他行中都没有进行任何修改,因此它们是printed。

    (在 GNU Awk 5.0.1 中测试)

    【讨论】:

      【解决方案3】:

      在任何 awk 中:

      $ awk 'NR==1{gsub(/^|;/,"&input_file.")} 1' file
      input_file.number;input_file.date;input_file.customer;input_file.key;input_file.amount
      

      但是 sed 的存在是为了做这样的简单替换,例如使用具有-E 的 sed 来启用 ERE(例如 GNU 和 BSD sed):

      $ sed -E '1s/^|;/&input_file./g' file
      input_file.number;input_file.date;input_file.customer;input_file.key;input_file.amount
      

      如果您使用的是 GNU 工具,那么您可以使用上述任何一种工具来一次更改所有 CSV 文件:

      awk -i inplace 'NR==1{gsub(/^|;/,"&input_file.")} 1' *.csv
      sed -i -E '1s/^|;/&input_file./g' *.csv
      

      【讨论】:

      • 对两者都进行了测试。 awk 似乎要快得多。谢谢
      • 这很难相信,因为 awk 在每个输入行所做的工作比 sed 做的要多。你确定你对每一个都进行了第 3 次运行计时并且你不只是看到缓存影响吗?
      【解决方案4】:

      还与awk 一起使用for 循环和printf

      awk 'BEGIN{FS=OFS=";"} NR==1{for (i=1; i<=NF; i++) printf "%s%s", "input_file." $i, (i<NF ? OFS : ORS)}' file
      input_file.number;input_file.date;input_file.customer;input_file.key;input_file.amount
      

      【讨论】:

        猜你喜欢
        • 2013-11-30
        • 2018-07-12
        • 1970-01-01
        • 2018-11-28
        • 2023-03-10
        • 2018-05-08
        • 1970-01-01
        • 2022-08-18
        相关资源
        最近更新 更多