我有四个数据集文件,我想根据第四个文件中的值更新一组三个文件。
- 文件_1包含名称。
- 文件_2他们的数字 ID。
- 文件_3包含 id 来自文件_1和文件_2,以及每对 id 组合对应的值。
- 文件_4包含一些新名称组合的值。
我需要做的是附加文件_4的新名字为文件_1和文件_2,并自动增量地为它们创建 id。然后将值插入文件_3根据新的 ID 组合。问题很简单,如下面的示例所解释的那样,使问题变得有点复杂的是逗号分隔的子字段的存在,例如“1,2,3”在一些数据集s。
我需要使用脚本来实现此目的,尽管我意识到它可能更容易使用sql。
文件_1
nid,vname
1,name1
2,name2
3,name3
文件_2
did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"
文件_3
nid,did,value
1,1,aa
1,2,gg
1,3,tt
2,1,aa
2,2,ag
2,3,at
3,1,aa
3,2,tt
文件_4
new_name,new_dataset,value
name1,"s7,s8",aa
name2,"s9,s10",gg
name8,"s1,s2,s3",aa
因此,三个更新的文件应如下所示:
文件_1_更新
nid,vname
1,name1
2,name2
3,name3
4,name8
文件_2_更新
did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"
4,"s7,s8"
5,"s9,s10"
文件_3_更新
nid,did,value
1,1,aa
1,2,gg
1,3,tt
1,4,aa
2,1,aa
2,2,ag
2,3,at
2,5,gg
3,1,aa
3,2,tt
4,1,aa
答案1
假设数据与您发布的完全相同,那么您可以在普通 bash 中执行以下操作。 (警告:就地修改文件。测试前请小心备份。)
管理前两个文件的几个函数:
next_id() {
file="$1"
# assumes file is sorted by id
echo $(( $(tail -n 1 $file|cut -d, -f1) + 1 ))
}
假设文件1和文件2在 id 列上排序,这将获取最后一行的第一部分并将其递增 1,生成下一个 id。
find_or_create_id() {
file="$1"
item="$2"
# check if we already have that item
id=$(grep -m 1 ",$item$" "$file" 2> /dev/null)
if [[ $? -ne 0 ]] ; then
# generate the next id, append
id=$(next_id "$file")
echo "$id,$item" >> "$file"
else
# got it already
id=${id/,*}
fi
echo "$id"
}
这将在前两个文件之一中查找项目(vname 或 dname)。如果找到,则返回现有的 id。如果没有,则生成下一个 id 并将其存储回文件中。
一旦你得到了正确的子字符串,主要部分就非常简单:
while read line ; do
col1=${line/,*} # everything up to first ,
col3=${line//*,} # everything after last ,
col2=${line%,*} # everything after first ,
col2=${col2#*,} # everything before last ,
id1=$(find_or_create_id file1 "$col1")
id2=$(find_or_create_id file2 "$col2")
# don't insert duplicates
if ! grep -m 1 -q "^$id1,$id2," file3 ; then
echo "$id1,$id2,$col3" >> file3
fi
done < <(tail -n +2 file4)
这会不是按顺序插入最后一个文件,您将在末尾附加新行。
话虽这么说,如果这些文件中的任何一个文件的大小都很大,那么数据库将是合适的。如果您不需要数据库服务器,请考虑 SQLite。
假设您不关心顺序 ID(只是它们是不同的),并且您已integer primary key autoincrement
为表 1 和表 2 添加了 ID(加上 vname 和 dname 上的唯一键),则更新看起来像(很可能是比该方法更微妙的方法insert or ignore
):
insert or ignore into tab1(vname) select distinct vname from tab4;
insert or ignore into tab2(dname) select distinct dname from tab4;
insert or ignore into tab3(id1,id2,value)
select tab1.id, tab2.id, tab4.value
from tab4
left join tab1 on tab1.vname = tab4.vname
left join tab2 on tab2.dname = tab4.dname;
SQLite 可以很好地处理"
文件中的 。
.separator ,
.import fileX tabX
做正确的事情™,至少对于您那里的样品是这样。
简单架构:
create table tab1 (id integer primary key autoincrement, vname text);
create unique index tab1_vname on tab1(vname);
create table tab2 (id integer primary key autoincrement, dname text);
create unique index tab2_dname on tab2(dname);
create table tab3 (id1 int, id2 int, value text,
constraint tab3_pk primary key(id1, id2));
create table tab4 (vname text, dname text, value text);
答案2
这是2/3的答案,使用*尼克斯软件工具。 文件_1_更新:
head -n 1 file_1 ; \
{ tail -n +2 file_1 | cut -d ',' -f 2 ; \
tail -n +2 file_4 | cut -d ',' -f 1 ; } | \
sort -n | uniq | nl -s ',' | tr -d ' '
输出:
nid,vname
1,name1
2,name2
3,name3
4,name8
文件_2_更新:
head -n 1 file_2 ; \
{ tail -n +2 file_2 | cut -d ',' -f 2- ; \
tail -n +2 file_4 | cut -d ',' -f 2- | \
rev | cut -d ',' -f 2- | rev ; } | \
sort -n | uniq | nl -s ',' | tr -d ' '
输出:
did,dname
1,"s1,s2,s3"
2,s4
3,"s5,s6"
4,"s7,s8"
5,"s9,s10"