你能不能帮我找到一个bash命令,它将加入/合并以下cvs文件" template.csv + file1.csv + file2.csv + file3.csv + ... + fileX.csv&# 34;进入" ouput.csv"。
对于template.csv中的每一行,连接fileX.csv中列出的关联值(如果存在),如下所示:
template.csv:
header
1
2
3
4
5
6
7
8
9
file1.csv:
header,value1
2,value12
3,value13
7,value17
8,value18
9,value19
file2.csv:
header,value2
1,value21
2,value22
3,value23
4,value24
file3.csv:
header,value3
2,value32
4,value34
6,value36
7,value37
8,value38
output.csv:
header,value1,value2,value3
1,,value21,
2,value12,value22,value32
3,value13,value23,
4,,value24,value34
5,,,
6,,,value36
7,value17,,value37
8,value18,,value38
9,value19,,
我的模板文件包含35137行 我已经开发了一个执行此合并的bash脚本(基于" do while"等等...)但性能并不好。生成output.csv太长了。我确信使用join,awk可以做同样的事情......但是我不知道如何......
重要更新
我的真实文件的第一列包含日期时间而不是简单的数字...所以脚本必须考虑日期和时间之间的空格...对不起更新!
现在应该使用以下csv文件设计脚本,例如:
template.csv:
header
2000-01-01 00:00:00
2000-01-01 00:15:00
2000-01-01 00:30:00
2000-01-01 00:45:00
2000-01-01 01:00:00
2000-01-01 01:15:00
2000-01-01 01:30:00
2000-01-01 01:45:00
2000-01-01 02:00:00
file1.csv:
header,value1
2000-01-01 00:15:00,value12
2000-01-01 00:30:00,value13
2000-01-01 01:30:00,value17
2000-01-01 01:45:00,value18
2000-01-01 02:00:00,value19
file2.csv:
header,value2
2000-01-01 00:00:00,value21
2000-01-01 00:15:00,value22
2000-01-01 00:30:00,value23
2000-01-01 00:45:00,value24
file3.csv:
header,value3
2000-01-01 00:15:00,value32
2000-01-01 00:45:00,value34
2000-01-01 01:15:00,value36
2000-01-01 01:30:00,value37
2000-01-01 01:45:00,value38
output.csv:
header,value1,value2,value3
2000-01-01 00:00:00,,value21,
2000-01-01 00:15:00,value12,value22,value32
2000-01-01 00:30:00,value13,value23,
2000-01-01 00:45:00,,value24,value34
2000-01-01 01:00:00,,,
2000-01-01 01:15:00,,,value36
2000-01-01 01:30:00,value17,,value37
2000-01-01 01:45:00,value18,,value38
2000-01-01 02:00:00,value19,,
答案 0 :(得分:2)
$ cat tst.awk
BEGIN { FS=OFS="," }
NR == FNR { key[++numRows] = $1 }
{ fld[$1,ARGIND] = $NF }
END {
for (rowNr=1; rowNr<=numRows; rowNr++) {
for (colNr=1; colNr<=ARGIND; colNr++) {
printf "%s%s", fld[key[rowNr],colNr], (colNr<ARGIND ? OFS : ORS)
}
}
}
$ awk -f tst.awk template.csv file1.csv file2.csv file3.csv
header,value1,value2,value3
2000-01-01 00:00:00,,value21,
2000-01-01 00:15:00,value12,value22,value32
2000-01-01 00:30:00,value13,value23,
2000-01-01 00:45:00,,value24,value34
2000-01-01 01:00:00,,,
2000-01-01 01:15:00,,,value36
2000-01-01 01:30:00,value17,,value37
2000-01-01 01:45:00,value18,,value38
2000-01-01 02:00:00,value19,,
以上使用ARGIND
的GNU awk,其他awks只添加一行FNR==1 { ++ARGIND }
。
答案 1 :(得分:1)
这应该有用(解释阅读评论):
#!/bin/sh
awk -F, -v file=0 '
FNR == 1 { # first line in the file
if(file == 0) { # if in first file (template.csv):
header = $1 # init header
} else {
header = header "," $2 # else append field name
}
next # forward to next line.
}
file == 0 { # if in first file:
key[FNR] = $1 # remember key
next # next line.
}
{
field[$1][file] = $2 # otherwise: remember field
}
ENDFILE { # at the end of a file:
file = file + 1 # increase counter
}
END { # in the end, assemble and
print header # print lines.
asort(key)
for(k in key) {
line = ""
for(i = 1; i < file; ++i) {
line = line "," field[key[k]][i]
}
print key[k] line
}
}
' template.csv file1.csv file2.csv file3.csv
答案 2 :(得分:1)
您可以使用多次调用join
:
join -t , -a 1 -o auto template.csv file1.csv | join -t , -a 1 -o auto - file2.csv | join -t , -a 1 -o auto - file3.csv
或者更清楚:
alias myjoin='join -t , -a 1 -o auto'
myjoin template.csv file1.csv | myjoin - file2.csv | myjoin - file3.csv
说明:
-t ,
指定字段分隔符(,
)-a 1
指示打印来自第一个文件的不可用行(假设头文件包含所有可能的标题)-o auto
控制格式设置,是打印空字段所必需的证明:
$ join -t , -a 1 -o auto template.csv file1.csv | join -t , -a 1 -o auto - file2.csv | join -t , -a 1 -o auto - file3.csv
header,value1,value2,value3
2000-01-01 00:00:00,,value21,
2000-01-01 00:15:00,value12,value22,value32
2000-01-01 00:30:00,value13,value23,
2000-01-01 00:45:00,,value24,value34
2000-01-01 01:00:00,,,
2000-01-01 01:15:00,,,value36
2000-01-01 01:30:00,value17,,value37
2000-01-01 01:45:00,value18,,value38
2000-01-01 02:00:00,value19,,
注意:
为此,必须在连接字段(在您的情况下为标题)中对文件进行排序。如果不是这种情况,您可以使用sort
命令。
答案 3 :(得分:0)
我会选择这个,但它肯定不是运行速度最快的解决方案,但对于您的数据,它会返回正确的结果并且代码很短:
#!/bin/bash
CONTENT=$(cat template.scv)
for line in $CONTENT; do
TMP=$(echo $line)
for file in file1.csv file2.csv file3.csv; do
RESULT=$(grep "^$line," $file | cut -d',' -f2)
TMP=$(echo $TMP,$RESULT)
done
echo $TMP
done
输出:
header,value1,value2,value3
1,,value21,
2,value12,value22,value32
3,value13,value23,
4,,value24,value34
5,,,
6,,,value36
7,value17,,value37
8,value18,,value38
9,value19,,
编辑:
我的代码缺少一个逗号(,
),因此对于较长的ID,它无法正常工作
编辑2:
那么它不是“不是最快的解决方案”,它真的很慢