Text-Processing

如何根據第四個文件更新三個 CSV 文件

  • June 28, 2016

我有四個csv文件,我想根據第四個文件中的值更新一組三個。

  1. file_1包含名稱。
  2. file_2他們的數字ID。
  3. file_3包含來自file_1file_2的 id ,以及對應於每對 id 組合的值。
  4. file_4包含來自一些新名稱組合的值。

我需要做的是將file_4的新名稱附加到file_1file_2,並自動為它們創建 id。然後根據新的 id 組合插入file_3中的值。正如下面的範例所解釋的,這個問題非常簡單,讓它有點複雜的是在某些csv中存在逗號分隔的子欄位,如“1,2,3”

我需要使用腳本來實現這一點,儘管我意識到使用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

假設數據與您發布的完全一樣,這是您可以在普通 bash 中執行的操作。(警告:就地修改文件。在測試之前小心備份。)

管理前兩個文件的幾個函式:

next_id() {
 file="$1"
 # assumes file is sorted by id
 echo $(( $(tail -n 1 $file|cut -d, -f1) + 1 ))
}

假設file1file2在 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

做 Right Thing™,至少對於您那裡的樣本。

簡單模式:

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);

引用自:https://unix.stackexchange.com/questions/164359