我需要构建一个 shell 脚本,它将所有可用的 CSV 文件连接成一个。所有这些 CSV 文件都具有相似的结构(即相同的标题和列数),并且这些文件具有共同的前缀GFP
。
例如:有一天我可能会有以下文件,
GFP_20210609.csv
GFP_20210610.csv
或者有时我可能有很多这样的文件。这里的问题是我不确定一天会出现多少个这样的文件(假设每天不超过 5 个 CSV 文件)。
我是 shell 脚本编写的新手。任何帮助将不胜感激。
sed 1d GFP_20210610.csv > GFP_20210610_NO_HEADER.csv
cat GFP_20210609.csv GFP_20210610_NO_HEADER.csv > GFP_FINAL.csv
答案1
尝试awk
awk 'NR==1||FNR>1' GFP*.csv > output.csv
这将从第二行开始打印每个文件的所有行(FNR>1
意味着每个文件的行计数器大于一)以抑制重复的标题,但请务必打印遇到的第一行(NR==1
),这是第一个文件的标题行文件。
然后输出被重定向到一个文件output.csv
。
该语法利用了这样一个事实:awk
如果在规则块 ( ) 之外找到的条件{ ...}
为 true,则将打印当前行。在这种情况下,我们可以完全省略规则块,因为我们实际上不想编辑,而只想过滤输入文件。
答案2
首先,我们将创建一次头文件,并将其保留在与其余 csv 文件相同的文件夹中
head -qn 1 GFP_20210609.csv > common.header
common_header.csv包含您选择的任何 csv 文件的第一行(根据您所说,所有 csv 文件都具有相同的标题)。您应该构建此文件一次并将其保留在同一目录中以供进一步使用。
head
命令首先输出n文本文件的行,在我们的头文件情况下为“1”。
tail
命令输出最后n文本文件的行。从“1”开始,我们将忽略所有 csv 文件的第一行,因为我们希望避免标头重复。
额外的 -q(安静)参数,head
并tail
防止我们在最终文件中不需要的额外输出信息。
下一行是脚本的源代码:
cat common.header > FINAL.csv && tail -qn 1 GFP_*.csv >> FINAL.csv
两个命令cat
和tail
都与 a 连接,&&
表示 tail
将运行仅有的如果cat
命令成功。
(*) 注意:tail -qn 1...
也可以写成tail -q -n 1...
和 是同一件事。
答案3
使用perl
我们在每个 eof 条件下显式关闭文件句柄,这是为了重置行计数器。对于绝对第一行,我们使用任何标量变量 $nr 并对其进行预递增。
perl -lne 'print if
++$nr==1||$.>1;
eof && close(ARGV);
' GFP_*.CSV > total.csv
GNU sed
与-s
单独处理文件的分离流选项一起使用。
{
head -n 1 "$(printf '%s\n' GFP_*.CSV |head -n 1 -)"
sed -se 1d GFP_*.csv
} > total.csv