【问题标题】:Awk argument too long when merging csv files合并 csv 文件时 awk 参数太长
【发布时间】:2020-12-19 15:48:28
【问题描述】:

我在一个文件夹中有超过 10000 个 csv 文件,我正在尝试使用 awk 逐行合并它们,但如果我运行此命令:
printf '%s\n' *.csv | xargs cat | awk 'FNR==1 && NR!=1{next;}{print}' *.csv > master.csv
我收到以下错误:
/usr/bin/awk: Argument list too longprintf: write error: Broken pipe

【问题讨论】:

    标签: bash csv awk merge


    【解决方案1】:

    使用 printfxargs 部分,您将 csv 文件的 内容 发送到 awk,但您也将文件名提供给 awk。选择其中一个:我建议:

    { printf '%s\n' *.csv | xargs awk 'FNR==1 && NR!=1{next;}{print}'; } > master.csv
    

    【讨论】:

    • 如果任何文件名包含空格,这将失败,您需要printf '%s\n' *.csv | xargs -d '\n' awk ... 甚至更好(因此它甚至适用于包含换行符的文件名)printf '%s\0' *.csv | xargs -d '\0' awk ...。话虽如此 - 该命令作为一个整体将不起作用,因为 OP 似乎试图跳过除第一个文件之外的每个文件的第一行,并且该命令会将文件名分批传递给 awk,因此多个“第一行”将是打印出来的。
    • head -n +1 whatever.csv; printf '%s\n' *.csv | xargs awk 'FNR>1' 可以完成这项工作,如果您可以选择 1 个 CSV 来运行 head 以获得第一行。
    • 如果目录中的文件名太多,xargs 将再次调用 awk 导致再次打印标题行。
    【解决方案2】:

    如果您的文件名不包含换行符,那么您可以这样做:

    printf '%s\n' *.csv | awk 'NR==FNR{ARGV[ARGC++]=$0; next} !c++ || FNR>1' -
    

    或者如果它们可以包含换行符,那么:

    printf '%s\0' *.csv | awk -v RS='\0' 'NR==FNR{ARGV[ARGC++]=$0; next} !c++ || FNR>1' RS='\0' - RS='\n'
    

    即让 awk 读取 CSV 文件名列表作为输入,而不是 shell 将其作为参数传递给 awk。即使您有数百万个 CSV 文件,这也可以工作。

    例如,给定这个输入:

    $ head -n +50 file*.csv
    ==> file1.csv <==
    Number
    1
    2
    
    ==> file2.csv <==
    Number
    10
    11
    12
    

    上面会产生这个输出:

    $ printf '%s\n' *.csv | awk 'NR==FNR{ARGV[ARGC++]=$0; next} !c++ || FNR>1' -
    Number
    1
    2
    10
    11
    12
    

    【讨论】:

      猜你喜欢
      • 2014-07-02
      • 1970-01-01
      • 1970-01-01
      • 2015-02-20
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2015-01-17
      • 1970-01-01
      相关资源
      最近更新 更多