为文件夹中的所有 csv 文件添加标题字段和数据行末尾的文件名

为文件夹中的所有 csv 文件添加标题字段和数据行末尾的文件名

我想在文件夹中所有 csv 文件的所有行的末尾添加文件名(不带扩展名)。所有文件都具有相同的标头。

假设我的文件夹中有两个文件 a.csv 和 b.csv。

a.csv 包含(第一行是标题)

num1,num2,num3  
1,2,3

b.csv 包含(第一行是标题)

num1,num2,num3    
4,5,6

我想要一个 .csv 文件(第一行是标题)

num1,num2,num3,filename  
1,2,3,a

我想要 b.csv 文件(第一行是标题)

num1,num2,num3,filename  
4,5,6,b

我怎样才能在 Unix 中做到这一点?

答案1

for file in *.csv
do
  filename=${file%.csv}
  sed -i -e "1s/\$/,filename/; 2,\$s/\$/,$filename/" "$file"
done
  1. 循环遍历*csv当前目录中的每个文件,
  2. 通过去掉尾随来准备文件名文本.csv
  3. -i使用 sed 就地 编辑文件:
    1. 仅在第 1 行上,搜索并用文本替换行尾(转义$,filename
    2. 在第 2 行到文件末尾 ( $) 上,搜索行末尾 ( $) 并将其替换为逗号和准备好的文件名

答案2

如果我正确理解了OP,那么“理想”的解决方案是(第1行不带扩展名,其余带有扩展名),使用GNU awk

gawk -F, -i inplace \
'BEGIN {
    OFS=",";
 }
 {
    if(FNR==1)
        name = gensub(/^(.*)\..*/, "\\1", "g", FILENAME);
    else
        name = FILENAME;

    print $0, name;
 }' *.csv

,句柄-F和赋值OFS=","将输入和输出字段分隔符设置为,

-i inplace意味着截断文件中的当前记录并将当前输出写入文件中。

gensub 内置保存不带扩展名的文件名,并且 print 语句打印所需的修改记录。

答案3

以下命令使用磨坊主( mlr) 读取 CSV 文件,并向每个文件添加一个名为 的新字段filename,其中包含当前文件的路径名(在命令行上给出)并.csv从末尾删除。

mlr -I --csv put '$filename = sub(FILENAME,"\.csv$","")' a.csv b.csv

使用-I,可以就地对文件进行更改,并且每个文件都被单独处理。其余的内容应该熟悉awk,还有一个好处是我们可以按名称引用字段。分配给新字段名称会创建该字段。

Miller 将自动引用任何需要引用的字段。

$ cat a.csv
num1,num2,num3
1,2,3
$ cat b.csv
num1,num2,num3
4,5,6
$ mlr -I --csv put '$filename = sub(FILENAME,"\.csv$","")' a.csv b.csv
$ cat a.csv
num1,num2,num3,filename
1,2,3,a
$ cat b.csv
num1,num2,num3,filename
4,5,6,b

相关内容