【问题标题】:Adding header to all .csv files in folder and include filename将标题添加到文件夹中的所有 .csv 文件并包含文件名
【发布时间】:2016-02-20 14:44:14
【问题描述】:

我是一个命令行新手,我正在尝试弄清楚如何将标题添加到多个 .csv 文件。新标头应具有以下内容:“TaxID”和“文件名”

我尝试了多个命令,如 sed、ed、awk、echo,但如果它有效,它只会更改它找到的第一个文件(我在命令中说 *.csv),我只能为 TaxID 管理这个。

任何人都可以帮助我将文件名也放入标题中并为我的所有 csv 文件执行此操作吗?

(注意,我使用的是 Mac)

谢谢!

【问题讨论】:

    标签: csv header


    【解决方案1】:

    在 perl 中,通过添加 TaxID,{filename} 的标头来修改文件,如果它认为已经存在则忽略添加标头。

    ls
    a.csv   b.csv
    
    cat a.csv
    1,a.txt
    2,b.txt
    
    cat b.csv
    3,c.txt
    4,d.txt
    
    ls *.csv | xargs -I{} -n 1 \
    perl -p -i -e 'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;' {}
    
    cat a.csv
    TaxID,a.csv
    1,a.txt
    2,b.txt
    
    cat b.csv
    TaxID,b.csv
    3,c.txt
    4,d.txt
    

    您可能想要创建一些文件的备份,或者在认真运行之前运行一些示例副本。

    解释:

    以 .csv 扩展名列出目录中的所有文件

    ls *.csv
    

    将 ls 命令的输出“管道”到 xargs 中,以便 perl 命令可以针对每个文件运行。 -I{} 允许随后使用{} 引用文件名。 -n 告诉 xargs 一次只将 1 个文件传递给 perl。

    | xargs -I{} -n 1
    

    -p打印输入(文件)的每一行

    -i就地修改文件

    -e执行以下代码

    perl -p -i -e
    

    Perl 将隐式循环遍历文件的每一行并打印它(由于-p)。如果我们还没有打印标题并且当前行看起来不像标题,则打印标题。

    'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;'
    

    这被替换为文件名。

    {}
    

    总而言之,在这个例子中要运行的命令是:

    perl -p -i -e 'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;' a.csv
    perl -p -i -e 'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;' b.csv
    perl -p -i -e 'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;' c.csv
    perl -p -i -e 'print "TaxID,{}\n" if !m#^TaxID# && !$h; $h = 1;' d.csv
    

    【讨论】:

    • 感谢 JRD 的魅力!您能否详细介绍一下您的代码中的哪个部分?
    【解决方案2】:

    这是一种方法,当然还有其他方法:

    $ for i in *.csv;do echo $i;cp "$i" "$i.bak" && { echo "TaxID,$i"; cat "$i.bak"; } >"$i";done
    

    这是一个示例运行:

    $ cat file1.csv
    1,2
    3,4
    $ cat file2.csv
    a,b
    c,d
    $ for i in *.csv;do echo $i;cp "$i" "$i.bak" && { echo "TaxID,$i"; cat "$i.bak"; } >"$i";done
    file1.csv
    file2.csv
    $ cat file1.csv.bak
    1,2
    3,4
    $ cat file1.csv
    TaxID,file1.csv
    1,2
    3,4
    $ cat file2.csv.bak
    a,b
    c,d
    $ cat file2.csv
    TaxID,file2.csv
    a,b
    c,d
    

    分解:

    $ for i in *.csv; do
    

    这会遍历当前目录中所有以.csv 结尾的文件。每个都会依次放入shell变量i中。

    echo $i;
    

    这只是回显当前文件名,以便您查看进度。可以放心地忽略它。

    cp "$i" "$i.bak"
    

    将当前文件(其名称在i)复制到备份。这既是为了在出现问题时保留文件,并为后续命令提供一些可供复制的内容。

    &&
    

    仅当cp 成功时才运行后续命令。如果您无法进行备份,请不要继续。

    {
    

    启动组命令。

    echo "TaxID,$i";
    

    输出所需的标题。

    cat "$i.bak";
    

    输出原始文件。

    }
    

    结束组命令。

    >"$i";
    

    将组命令的输出(新标头和原始文件的内容)重定向到原始文件。这样就完成了一个文件。

    done
    

    完成所有文件的循环。

    为了好玩,这里有几种其他方法(一个 JRD 打败了我),包括使用ed

    $ for i in *.csv;do echo $i;perl -p -i.bak -e 'print "TaxID,$ARGV\n" if $. == 1' "$i";done
    $ for i in *.csv;do echo $i;echo -e "1i\nTaxID,$i\n.\nw\nq\n" | ed "$i";done
    

    【讨论】:

    • 谢谢blm!我之前尝试过一个类似的命令(for i in *csv),但我认为我做错了,它只适用于它找到的第一个文件。也谢谢你详细的代码解释!
    • @Kay 不客气。很难说为什么你的尝试会在没有看到整个命令行的情况下失败,但你是在正确的轨道上。
    • 谢谢blm!你的帖子真的帮助我节省了大量时间。这对我很有用。
    • @SankarChandraBose 不客气,很高兴我能提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2015-12-02
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    相关资源
    最近更新 更多