Как обновить три файла CSV на основе четвертого файла

Если у вас есть TOTPUT в этой системе, вы можете использовать:

tput smcup ; top ; tput rmcup

Вы можете поместить это в псевдониме, если вы предпочитаете всегда использовать это, когда вы инфицируете Вершина :

alias top='tput smcup ; top ; tput rmcup'
0
28.06.2016, 05:17
2 ответа

Вот что вы можете сделать в обычном bash, если данные будут в точности такими, как вы опубликовали. ( Предупреждение : изменяет файлы на месте. Будьте осторожны, сделайте резервные копии перед тестированием.)

Пара функций для управления первыми двумя файлами:

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

Предполагается, что file1 и file2 сортируются по столбцу 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) в одном из первых двух файлов. Если он найден, верните существующий идентификатор. Если нет, сгенерируйте следующий идентификатор и сохраните его обратно в файл.

Основная часть становится довольно простой, если у вас есть правильные подстроки:

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, если вам не нужен сервер базы данных.

Предполагая, что вас не интересуют последовательные идентификаторы (только то, что они разные), и вы установили целочисленные идентификаторы автоинкремента первичного ключа для таблиц 1 и 2 (плюс уникальные ключи для vname и dname), обновление будет выглядеть так (скорее всего, существуют более тонкие способы, чем подход вставки или игнорирования ):

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);
3
28.01.2020, 02:28

Вот 2/3 ответа с использованием программных средств * nix . file_1_updated :

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

file_2_updated :

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"
0
28.01.2020, 02:28

Теги

Похожие вопросы