LINUX.ORG.RU

left join для csv на bash

 ,


0

1

Периодически бывают задачи, где нужно объединить данные из нескольких не очень больших csv файлов.

Сделать что-то вроде select f1.*,f2.* from 1.csv f1 left join 2.csv f2 on f1.c = f2.c;

Обычно я делаю какую-то одноразовую ерунду типа такой:

tail -n +2 1.csv | (while read -r line; do 
	colC="$(echo "$line" | awk -F',' '{print $3}')";
	matches="$(tail -n +2 2.csv | awk -F',' '{print $2"|"$0}' | grep -E "^$colC\|" | sed 's/^[^|]*|//;s/^/;/' | tr -d '\n');"
	echo "$line$matches"; 
done)

исходные файлы:

1.txt:

A,B,C
foo1,bar1,10
foo2,bar3,20
foo3,bar3,30

__
2.txt:

E,C,D
buz20,20,20
buz10,10,10
buz11,10,11

Выхлоп:

foo1,bar1,10;buz10,10,10;buz11,10,11;
foo2,bar3,20;buz20,20,20;
foo3,bar3,30;

Как подобное делать нормальнее? Больше интересует короткий и понятный вариант чем производительный.

★★★★★

python, pandas.DataFrame, недавно распробовала, это вещь

alpha ★★★★★
()
Ответ на: комментарий от Anoxemian

берешь субд, импортируешь, делаешь join, экспортируешь

Тут много лишнего - создать временную схему, описать структуру таблиц. csv могут быть несколько кривыми.

Или можно какой-то пример как быстро импортировать csv, например, в sqlite?

csvkit наверное стоит попробовать, но далеко не во всех репозиториях имеется. Хочется что-то более стандартное.

https://csvkit.readthedocs.io/en/1.0.2/tutorial/3_power_tools.html#csvjoin-me...

Tanger ★★★★★
() автор топика
Ответ на: комментарий от Bagrov

paste -d \; 1.txt 2.txt /dev/null | tail -n +2

нет. Я сопоставляю строки по ключу 'C', а в твоем варианте просто выводятся оба файла.

Tanger ★★★★★
() автор топика
Ответ на: комментарий от dnb

интересно. А если csv без заголовка - оно как колонки именует? И как будет работать, если где-то в середине будут пустые строки/какой-то мусор?

Tanger ★★★★★
() автор топика

Если можно использовать join из coreutils. Однострочник (надеюсь сам осилишь что тут происходит и модеры тоже):

join -t, -a1 -13 -22 <(tail +2 1.txt | sort -t, -k3) <(tail +2 2.txt | sort -t, -k2)
anonymous
()
Ответ на: комментарий от anonymous

join из coreutils

Да, то что нужно. Спасибо.

Tanger ★★★★★
() автор топика

Как подобное делать нормальнее? Больше интересует короткий и понятный вариант чем производительный.

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

#!/usr/bin/env bash

in1=1.csv
in2=2.csv
col1=3
col2=2

{ read lf1
  while read lf1; do
        IFS=, read -a a1 <<< "$lf1"
        [[ -z ${a1[col1-1]} ]] && continue
        m=';'
        { read lf2
          while read lf2; do
                IFS=, read -a a2 <<< "$lf2"
                [[ ${a1[col1-1]} = "${a2[col2-1]}" ]] && m+="$lf2;"
          done
        } < "$in2"
        echo "$lf1$m"
  done; } < "$in1"

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.