Как отсортировать первый файл (csv )на основе ключей второго файла

Не совсем, нет. Буферизация устанавливается для каждого процесса -с помощью вызова setbuf(3), языки сценариев предлагают различные степени контроля над (TCL :полным, Perl|Python|Ruby :неполным, Shell :вообще нет ). Вам нужно будет использовать оболочку, которая имитирует терминал (unbuffer, expect, tmux )или попробовать исправление непереносимых системных вызовов (stdbuf), чтобы попытаться повлиять на то, как выполняется вывод, или добавить код в каждое приложение. так что вывод может быть установлен как небуферизованный, буферизованный по строкам или буферизованный по блокам (или любое другое подмножество из тех, что предлагает язык, если таковые имеются ). Некоторые приложения уже будут иметь для этого флаги, например. -lиз tcpdump, или несложно добавить такой код:

#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);

GetOptions( 'l' => \my $Flag_Unbuffer ) or exit 64;

STDOUT->autoflush(1) if $Flag_Unbuffer;

print "hi\n" for 1..4;
sleep 10;

Если это сохранить как lflagи сделать исполняемым, разницу в поведении можно будет наблюдать, запустив:

$./lflag | cat

или

$./lflag -l | cat
5
20.09.2020, 15:40
3 ответа

Если ваши данные не слишком велики, это простое решение с квадратичной сложностью:

cat sort_keys.txt | while read key ; do egrep "^$key " file1.csv ; done

Для добавления/удаления заголовка добавьте команды headи tailпо мере необходимости.

2
18.03.2021, 23:03

Просто ради добавления варианта можно запустить маршрут steeldriver , но упростить логику, отказавшись от использования как функции, так и awkвстроенного -массива, такого как как PROCINFO. Это работает только для ключей сортировки, которые не повторяются.

$ gawk '
        NR==FNR {o[$1]=FNR; next}  # map keys to numerical order in 1st input file `sort_key.txt`
        FNR==1 {print; next}       # print header of 2nd input file `file.csv`; go to next record
        {a[$1]=$0}                 # after header, place each record of `file.csv` in array `a`.
        END {
            for(i in o) b[o[i]]=i; # make new array, `b`, with swapped keys and values from array `o`.
            n=length(o) 
            for (j=1;j<=n;j++) print a[b[j]]
        }
       ' sort_key.txt file.csv

COLUMN1 COlUMN2
cat animal
dog animal
apple fruit
cow animal
3
18.03.2021, 23:03

Для этого можно использовать join. Изman join:

For each pair of input lines with identical join fields, write a line to standard output. The default join field is the first, delimited by blanks.

Обратите внимание, что первая строка не должна быть отсортирована.

TLDR:

head -n 1 file1.csv; join -1 2 <(cat -n sort_keys.txt | sort -k 2) <(tail -n +2 file1.csv | sort) | sort -n -k 2 | awk '{ print $1, $3 }'сделает свое дело.

Пояснения

В общем,:

  • извлечь первую строку файла file1.csv
  • объединить оставшуюся часть файла1.csv с ключами сортировки _в первом поле
  • сортировать результат в порядке сортировки _ключей

Кроме того, joinнеобходимо отсортировать файлы.

Это приведет нас к:

  • в качестве первого ввода, номер (в предварительном поле )файл ключей сортировки _(, чтобы иметь возможность использовать этот исходный порядок в конце )и сортировать по второму полю

cat -n sort_keys.txt | sort -k 2

  3 apple
  1 cat
  4 cow
  2 dog
  • в качестве второго входа мы берем CSV-файл, пропуская первую строку, и сортируем его по первому полю.

tail -n +2 file1.csv | sort

 apple fruit
 cat animal
 cow animal
 dog animal
  • затем мы можем соединить все вместе, используя второе поле для первого процесса(-1 2):

join -1 2 <(cat -n sort_keys.txt | sort -k 2) <(tail -n +2 file1.csv | sort)

 apple 3 fruit
 cat 1 animal
 cow 4 animal
 dog 2 animal
  • результат объединения теперь можно сортировать по второму полю, числовому (в случае, если ключи сортировки _имеют более 9 записей ), и мы сохраняем только 1-е и 3-е поля

`... | сортировать -n -k 2 | awk '{напечатать $1, $3}'

 cat animal
 dog animal
 apple fruit
 cow animal
  • наконец, добавьте это к первой строке файла file1.csv

head -n 1 file1.csv; join -1 2 <(cat -n sort_keys.txt | sort -k 2) <(tail -n +2 file1.csv | sort) | sort -n -k 2 | awk '{ print $1, $3 }'

 COLUMN1 COlUMN2
 cat animal
 dog animal
 apple fruit
 cow animal

Идем дальше

В зависимости от ваших реальных данных вам придется настроить номера полей и разделитель полей.

Вы также можете сохранить строки данных, ключ которых не находится в ключах сортировки _, и/или сохранить строки ключей сортировки _, не имеющих соответствующих строк данных (см. -aвариант соединения ).

Приятного использования join!

1
18.03.2021, 23:03

Теги

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