【问题标题】:Split file on the value of a certain column into separate files and also include the header将某个列的值的文件拆分为单独的文件,并包括标题
【发布时间】:2015-11-01 17:54:41
【问题描述】:

完整文件.csv:

animal,number
rabbit,1
fish,2
mouse,1
dog,1
lizard,2
cat,2

我想在第二列的值上拆分文件, 并使用了这个命令:

awk 'BEGIN {FS = ","}; {print > ("file"$2".csv")}' fullfile.csv

输出:

file1.csv

rabbit,1
mouse,1
dog,1

file2.csv

fish,2
lizard,2
cat,2

但是 file1.csv 或 file2.csv 中没有标题,所以我尝试像这样添加它:

awk 'BEGIN {FS = ","}; NR==1 { print } {print > ("file"$2".csv")}' fullfile.csv

但标题打印到命令行而不是转到每个文件。如何让标题包含在每个文件中?

【问题讨论】:

  • 我个人的偏好是不要在第一行使用 awk,而对两个文件都以 head -1 开头。但是我很确定如果您引入if 并使用两个打印语句打印到这两个文件,您可以使用 awk 来做到这一点。但是,如果文件的数量不是固定的并且由文件的第二列的内容决定,则需要一些创造力......然后为它编写 perl 或 bash 脚本可能会更容易......
  • 感谢您的输入。它不必在 awk 中。我考虑过使用 awk 行,然后使用 sed 将第一个标题添加到每个文件:sed -i - e 'header line' file.csv ......但这需要复制和粘贴标题行并在每次我需要运行它时将其替换到脚本中......希望有一种更简单、更不容易出错的方法。跨度>

标签: bash csv awk


【解决方案1】:

您还可以使用awk -F","awk 脚本之外指定字段分隔符。

NR==1 时可以将标头存储为变量。将文件编号存储在数组中,如果编号不在数组中,则仅写入一次标题。一旦值在数组中,您只需按照之前的设置将这些行写入各自的文件:

awk -F"," 'NR==1{header=$0}NR>1&&!a[$2]++{print header > ("file"$2".csv")}NR>1{print > ("file"$2".csv")}' fullfile.csv

输出:

file1.csv

animal,number
rabbit,1
mouse,1
dog,1

file2.csv

animal,number
fish,2
lizard,2
cat,2

【讨论】:

  • 您能解释一下脚本的 'NR==1{header=$0}NR>1&&!a[$2]++ 部分吗??
  • @Pooja25 当然。 NR==1{header=$0} 表示如果我们在第一行,则将整行存储在变量 header 下。我们移动的下一个表达式测试通过带有NR>1 的标头,并且还使用带有!a[$2]++awk 数组技巧——这个构造测试$2 是否不在 数组中如果不是,它会添加它。因此,当我们第一次在$2 中遇到新值时,比如1,我们会启动一个名为file1.csv 的新文件,该文件以标题开头。我们将1 存储在数组中,因此file1.csv 的标头只会被写出一次。
  • 非常感谢。对此,我真的非常感激。还有一个问题,为什么我们需要使用 ("file"$2".csv")}NR>1{print > ("file"$2".csv")} 两次?我的意思是第二个 print > ("file"$2".csv") 做什么?
  • 文件名 ("file"$2".csv") ,$2 值在我不想要的文件名上用双引号括起来。现在文件名是:ABC."123".csv,我要ABC.123.csv。你能帮忙吗?
  • @Pooja25 我们使用 print 语句两次的原因是我们第一次打印标题时,只会在NR>1&&!a[$2]++ 时发生。下一个打印是打印实际数据,只需要NR>1。通常只发生一次打印,但如果在第 2 列中遇到新值,我们将创建一个新文件,因此我们需要标题,因此需要两个打印语句。
【解决方案2】:

这是一个更简单的 awk 命令,格式更好。

awk -F, '
NR==1 {hdr=$0; next}
{fn="file" $2 ".csv"}
!seen[$2]++{print hdr > fn}
{print > fn}' fullfile.csv

样本输出

$ for i in file*.csv; do echo $i; cat $i; echo; done
file1.csv
animal,number
rabbit,1
mouse,1
dog,1

file2.csv
animal,number
fish,2
lizard,2
cat,2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    相关资源
    最近更新 更多