Text-Processing
如何根據第四個文件更新三個 CSV 文件
我有四個csv文件,我想根據第四個文件中的值更新一組三個。
- file_1包含名稱。
- file_2他們的數字ID。
- file_3包含來自file_1和file_2的 id ,以及對應於每對 id 組合的值。
- file_4包含來自一些新名稱組合的值。
我需要做的是將file_4的新名稱附加到file_1和file_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 )) }
假設file1和file2在 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);