我是脚本新手。遇到 Unix 中的文件合并问题。正在寻找一些方向并偶然发现了这个网站。我看到了很多很棒的帖子和回复,但找不到解决我的问题的方法。非常感谢任何帮助..
我有三个 csv 文件 -> Apex_10_Latest.csv、Apex_20_Latest.csv、Apex_30_Latest.csv。这 3 个文件中的列数各不相同。通常,根据编号,最新文件可能会在末尾附加一些新列。所以我想获取最新的标头并将所有 3 个文件中的数据堆叠到一个新文件 Apex.csv 中。当堆叠旧文件中的数据时,该文件的列数可能少于最新文件的列数,我希望使用适当的分隔符将数据填充为空。
此外,还必须对同一文件夹中的多组文件(每个文件 3 个)递归地完成此操作。 - Apex_10_Latest.csv、Apex_20_Latest.csv、Apex_30_Latest.csv - 合并到 Apex.csv - Code_10_Latest.csv、Code_20_Latest.csv、Code_30_Latest.csv - 合并到 Code.csv - Trans_10_Latest.csv、Trans_20_Latest.csv、Trans_30_Latest.csv - 合并导入 Trans.csv
以下是源文件和预期目标文件的格式...源文件:
Apex_30_Latest.csv:
A B C D
1,2,3,4
2,3,4,5
3,4,5,6Apex_20_Latest.csv:
甲、乙、丙
4,5,6
5,6,7
6,7,8Apex_10_Latest.csv:
甲、乙
7,8
8,9
9,10
预期目标文件:
- Apex.csv
A B C D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,,
5,6,7,,
6,7,8,,
7,8,,,
8, 9,,,
9,10,,,
谢谢...
答案1
与米勒 (http://johnkerl.org/miller/doc/)像往常一样很容易
mlr --csv unsparsify Apex_*_Latest.csv
给你
A,B,C,D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,
5,6,7,
6,7,8,
7,8,,
8,9,,
9,10,,
答案2
cat $(ls -1 Apex_*_Latest.csv | sort -nr -k2 -t'_') | awk -F"," '{
if (NR==1){
nfm=NF};
for (i=1;i<=nfm;i++) {
printf $i","};
print ""}' >Apex.csv
您可以sort
根据第二个字段 (30,20,10..) 和cat
文件反转文件名,以便列数最高的行排在前面。
然后你可以从第一行awk
获得最高的列数NF
NR
if (NR==1){nfm=NF}
然后运行for
循环,直到i
(列号)大于或等于nfm
字段 no 中的打印值,i
后跟“,”。如果该字段没有值i
(当列少于最新文件时发生),它将只打印,
.
答案3
我认为前面的答案是最好的,我只是展示了一种不同的方法,因为我已经很多年没有使用 awk 了,因为 perl 和 python 变得很大。我认为 awk 很好,只是 shell、sed、python 和/或 perl 的混合更适合我的工作。
然而,在这种情况下,我认为任何人都可以看到 awk 解决方案更简洁且更易于阅读。想想看,我想我听说过 awk 被称为命令行电子表格,或者类似的东西。 :-)
根据原始帖子,我选择让 ls 命令按文件修改时间对文件名进行排序,而不是依赖文件名格式。一个是六个,另一个是六个。
因此,为了进行比较,这里有一个高效、可移植、模块化(?!)、纯 shell 版本的解决方案:
#!/bin/sh
get_commas() {
sed 's/[^,]//g; 1q' "$@"
}
get_extra_commas() {
local maxcommas="$1"
local file="$2"
local new_commas=$(get_commas "$file")
local extra_commas=""
while [ "${new_commas}${extra_commas}" != "${maxcommas}" ]
do
extra_commas=",$extra_commas"
done
echo "$extra_commas"
}
unset header
ls -t Apex*.csv |
while read filename
do
if [ -z "$header" ]
then
header="$(sed 1q "$filename")"
commas=$(echo "$header" | get_commas)
echo "$header"
fi
extra_commas=$(get_extra_commas $commas "$filename")
sed "1d; s/\$/$extra_commas/" "$filename"
done
答案4
这是在中实现的答案磨坊主:
$ cat rect.mlr
for (k,v in $*) {
@fields[k] = v; # retain already-seen field names
}
for (k,v in @fields) {
if (isabsent($[k])) {
$[k] = "";
}
}
$ mlr --csvlite put -f rect.mlr Apex_30_Latest.csv Apex_20_Latest.csv Apex_10_Latest.csv
A,B,C,D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,
5,6,7,
6,7,8,
7,8,,
8,9,,
9,10,,
由于 Miller 本质上处理命名列,因此标题行管理变得更简单。