【问题标题】:Split single column of csv horizontally in bash into multiple smaller csv files in BASH将 bash 中的单列 csv 水平拆分为 BASH 中的多个较小的 csv 文件
【发布时间】:2013-04-01 16:07:59
【问题描述】:

我正在使用 bash,并且我在 csv 中有一个 column (not row) 没有标题 - samplefile.csv

111 
222 
333 
444 
555 
666 
777 
888

在这种情况下,我希望将其拆分为(比如说)2 个 4 行和单列 的 csv 文件(如果奇数表示 9 行,则 5 和 4)带有数据的 csv 文件

output1.csv(1 列 4 行)

111
222
333
444

和 output2.csv(1 列 4 行)

555
666
777
888

Csplit 不会创建 csv 文件,如此处所示 split a file into x files where file names are numbered

有什么建议吗?

【问题讨论】:

  • 如果您的示例文件是单列,为什么它是一行而不是八行?
  • 我对您链接到的问答的阅读是 csplit 确实可以用于 CSV 文件。我错过了什么吗?
  • @MarkReed:我希望将包含 8 个元素的 csv 文件的第一列(总共 1 列有 8 个元素)拆分为 2 个单独的 csv 文件,其中前四个元素在一个列中以及第二个 csv 文件,其中元素 5-8 在单个列中。希望这能回答您的问题。
  • @Simon:csplit 拆分一个 csv 文件,但不会在拆分后创建一个 csv 文件。能做到吗?

标签: bash csv awk split


【解决方案1】:

这对我有用。我在 excel 中打开了生成的 csv,它的格式正确。我还没有弄清楚如何删除尾随逗号,但根据许多 csv 格式定义,这似乎是可以接受的。第一个 xargs 调用将逗号添加到文件的每一行。第二个 xargs 将四个批处理。如果您将其重定向到文件 (> new.csv),它可能就是您要查找的内容。

>cat my.csv
111
222
333
444
555
666
777
888 
>cat my.csv | xargs -n 1 -i echo \{\}, | xargs -n 4 
111, 222, 333, 444,
555, 666, 777, 888,

【讨论】:

  • 我希望将 1 个垂直列 8 拆分为 2 个垂直列 4 的 csv 文件。您创建了 2 行 4。不完全是,但感谢您的回复!
  • 天哪!晚上工作太晚,无法慢慢阅读您的问题。
【解决方案2】:

我可以使用split 命令。

n=awk 'END{print int(NR/2)}' file_name && split -l $n 文件名

cat output1
111
222
333
444


cat output2 
555
666
777
888

【讨论】:

    【解决方案3】:

    你要找的只是分割命令,带有-n选项

    split -nl/2 input output
    

    将为您完成这项工作。

    来自拆分手册页:

    -n, --number=CHUNKS
                  generate CHUNKS output files.  See below
     CHUNKS may be: N       split into N files based on size of input K/N     output Kth of N to stdout l/N     split into N  files  without  splitting  lines  l/K/N
           output Kth of N to stdout without splitting lines r/N     like 'l' but use round robin distribution r/K/N   likewise but only output Kth of N to stdout
    

    【讨论】:

      【解决方案4】:

      这很简单,awk 试试awk '{print $0 > ("output"i+1".csv")}!(NR%4){i++}' file

      演示:

      $ ls 
      file
      
      $ cat file 
      111 
      222 
      333 
      444 
      555 
      666 
      777 
      888
      
      $ awk '{print $0 > ("output"i+1".csv")}!(NR%4){i++}' file
      
      $ ls
      file  output1.csv  output2.csv
      
      $ cat output1.csv 
      111 
      222 
      333 
      444 
      
      $ cat output2.csv 
      555 
      666 
      777 
      888
      

      说明:

      取模运算符是这里的关键,我们希望在每四行之后分割输入行:

      $ awk '{print NR%4,$0}' file
      1 111
      2 222
      3 333
      0 444
      1 555
      2 666
      3 777
      0 888
      

      每四分之一的四的模数(余数)当然为零,因此我们使用这个事实来增加文件计数器。!(NR%4)NR%4==0 的简写,因为零评估为假,并且当我们希望块 {i++} 执行时,NR%4 为零,所以我们否定它。

      $ awk '{print NR%4,$0,"output"i+1".csv"}!(NR%4){i++}' file
      1 111 output1.csv
      2 222 output1.csv
      3 333 output1.csv
      0 444 output1.csv
      1 555 output2.csv
      2 666 output2.csv
      3 777 output2.csv
      0 888 output2.csv
      

      【讨论】:

      • +1 是正确的解决方案,但您可以使用print 而不是print $0,更重要的是,在重定向运算符右侧使用字符串连接时,您必须使用("output"i+1".csv") 作为顺序重定向与字符串连接的优先级在标准中未定义,因此某些 awks 可以将未加括号的 > "output"i+1".csv" 视为 > "output";(i+1".csv")
      • @EdMorton 感谢您的第二个提示,我当然知道第一个提示,但这次我更清楚地表达了简洁性。
      • 是的,我想。如果我不得不提到第二个,我什至不会提到第一个。
      • 这在我直接传递数字时有效。谢谢。但我似乎无法将 (NR%4) 作为 (NR%$VariableName) 传递。有什么建议吗?
      • 非常感谢@sudo_O 你是个救世主!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      • 2020-03-22
      相关资源
      最近更新 更多