【发布时间】:2016-02-20 14:44:14
【问题描述】:
我是一个命令行新手,我正在尝试弄清楚如何将标题添加到多个 .csv 文件。新标头应具有以下内容:“TaxID”和“文件名”
我尝试了多个命令,如 sed、ed、awk、echo,但如果它有效,它只会更改它找到的第一个文件(我在命令中说 *.csv),我只能为 TaxID 管理这个。
任何人都可以帮助我将文件名也放入标题中并为我的所有 csv 文件执行此操作吗?
(注意,我使用的是 Mac)
谢谢!
【问题讨论】:
我是一个命令行新手,我正在尝试弄清楚如何将标题添加到多个 .csv 文件。新标头应具有以下内容:“TaxID”和“文件名”
我尝试了多个命令,如 sed、ed、awk、echo,但如果它有效,它只会更改它找到的第一个文件(我在命令中说 *.csv),我只能为 TaxID 管理这个。
任何人都可以帮助我将文件名也放入标题中并为我的所有 csv 文件执行此操作吗?
(注意,我使用的是 Mac)
谢谢!
【问题讨论】:
在 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
【讨论】:
这是一种方法,当然还有其他方法:
$ 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
【讨论】: