目前我们收到多个大型CSV文件,我们需要将其插入/更新到数据库中。数据库的模式不改变。我们只需要在标题数据库中声明的特定顺序的特定列。这些可以在任意点改变。我们收到的CSV文件也可以随时改变顺序。
所以我所做的是管道所需的列从头数据库到这个脚本($TEMP_FILE),并从收到的CSV ($REC_CSV)提取我所需的列。
目前运行正常:
awk 'NR==FNR{
Clm=Clm (Clm?"|":"")$1
next
}
FNR==1{
for (i=1;i<=NF;i++)
{
if (match($i,Clm))
{
Ar[++n]=i
}
}
}
FNR>=2{
for (i=1; i<=n; i++)
{
printf (i<n)? $(Ar[i]) FS : $(Ar[i])
}
printf "n"
}' FS="|" ${TEMP_FILE} $REC_CSV >> $MY_NEW_CSV_WITH_HEADER
TEMP_FILE(From Header DB):
id|anotherId|hahahaIdontExist|timestamp
Input-CSV:
id|timestamp|anotherId|thisId|andThisId|andAnotherId
1|2:00|34|44|44|41
2|2:00|34|45|44|41
3|3:00|35|46|44|41
输出:
id|anotherId|timestamp
1|34|2:00
2|34|2:00
3|35|3:00
但是这里有一个问题:hahahaIdontExist
因为它模糊地暗示了这个变量一开始就不应该存在,但它也需要在输出中以空FS出现。
所需输出:
id|anotherId|hahahaIdontExist|timestamp
1|34||2:00
2|34||2:00
3|35||3:00
因为我相信它是更容易(和更安全)保持第一个脚本(我尝试了1000个草案),你有一个关于如何填写不存在的列到输出的建议吗?
问好根据您展示的样品,您可以尝试以下操作吗?在GNUawk
下编写和测试。
awk '
BEGIN{
FS=OFS="|"
}
FNR==NR{
for(i=1;i<=NF;i++){
arr[$i]=i
}
print
next
}
FNR==1{
PROCINFO["sorted_in"] = "@val_num_asc"
num=split($0,currVal,"|")
for(k=1;k<=num;k++){
currVal1[currVal[k]]=k
}
for(u in arr){
if(u in currVal1){
realArr[++count]=currVal1[u]
delete arr[u]
}
else{
realArr[++count]="NA"
}
}
next
}
{
for(k=1;k<=count;k++){
printf("%s%s",(realArr[k]!="NA"?$realArr[k]:OFS),(k==count?ORS:realArr[k]!="NA"?OFS:""))
}
}
' temp_file input.csv
示例输出如下:
id|anotherId|hahahaIdontExist|timestamp
1|34||2:00
2|34||2:00
3|35||3:00
我会这样做:
awk -F| -v outHeader="$(< "$TEMP_FILE")" '
NR == 1 {
for (i = 1; i <= NF; ++i)
inTitleToIdx[$i] = i
idxEmptyField = NF+1000
maxOutIdx = split(outHeader, outIdxToTitle)
for (i = 1; i <= maxOutIdx; ++i) {
inIdx = inTitleToIdx[outIdxToTitle[i]]
outIdxToInIdx[i] = inIdx == "" ? idxEmptyField : inIdx
}
print outHeader
}
NR > 1 {
sep=""
for (i = 1; i <= maxOutIdx; ++i) {
printf "%s%s", sep, $outIdxToInIdx[i]
sep = FS
}
print ""
}
' inputFile
注意:您不需要临时文件$TEMP_FILE
。也可以写成-v outHeader="id|anotherId|hahahaIdontExist|timestamp"
或-v outHeader="$(commandThatReadsTheHeaderFromTheDB)"