Bash 将特定列的值上的文件拆分为单独的文件,并包括标题

Bash 将特定列的值上的文件拆分为单独的文件,并包括标题,bash,csv,awk,Bash,Csv,Awk,fullfile.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 animal,number rabbit,1 mouse,1 dog,1 文件2.csv

fullfile.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
animal,number
rabbit,1
mouse,1
dog,1
文件2.csv

fish,2
lizard,2
cat,2
animal,number
fish,2
lizard,2
cat,2
但是,file1.csv或file2.csv中没有标题,因此我尝试这样添加它:

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

但是标题会打印到命令行,而不是每个文件。如何获取要包含在每个文件中的标题?

您还可以使用
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

rabbit,1
mouse,1
dog,1
animal,number
rabbit,1
mouse,1
dog,1
文件2.csv

fish,2
lizard,2
cat,2
animal,number
fish,2
lizard,2
cat,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

我个人的偏好是不在第一行使用awk,而只是在两个文件中都使用
head-1
。但我很确定,如果引入
if
并使用两个print语句打印到两个文件中,您可以使用awk来实现这一点。但是,如果文件的数量不是固定的,并且不是由文件第二列的内容决定的,那么它需要一些创造性。。。那么为它编写perl或bash脚本可能会更容易…感谢您的输入。。它不必在awk中。。我考虑过使用awk行,然后使用sed:sed-I-e'headerline'file.csv将第一个头添加到每个文件中。。。但这需要复制和粘贴标题行,并在每次需要运行此脚本时将其替换到脚本中。。。希望有一种更简单、更不容易出错的方法。你能解释一下'NR==1{header=$0}NR>1&&!脚本的[$2]++部分???@Pooja25当然
NR==1{header=$0}
表示如果我们在第一行,则将整行存储在变量
header
下。我们移动的下一个表达式测试通过了
NR>1的头,还使用了
awk
数组技巧和
![$2]+
——此构造测试
$2
是否不在数组中,如果不在数组中,则添加它。因此,当我们第一次在
$2
中遇到一个新值时,比如说
1
,我们会启动一个名为
file1.csv
的新文件,从标题开始。我们将
1
存储在数组中,因此
file1.csv
的标题将只写入一次。非常感谢。我真的很感激。还有一个问题,为什么我们需要使用(“文件“$2.csv”)}NR>1{print>(“文件“$2.csv”)}两次?我的意思是第二次打印>(“文件“$2.csv”)做什么?文件名(“文件“$2.csv”),$2值在文件名上用双引号引起来,这是我不想要的。现在文件名是:ABC.123.csv,我想要ABC.123.csv。@Pooja25我们使用print语句两次的原因是我们第一次打印标题,这只发生在
NR>1&&!a[$2]+
。下一次打印是打印实际数据,只需要
NR>1
。通常只进行一次打印,但如果在第2列中遇到一个新值,我们将创建一个新文件,因此我们需要头和两个打印语句。