Поскольку файлы отсортированы¹, вы можете объединить их построчно с помощью утилиты join
в coreutils
:
$ join -j2 -o auto -e 0 -a 1 -a 2 41144043-a 41144043-b
1009 3 5
1010 0 3
1012 7 0
1013 2 1
1014 8 0
Все эти параметры необходимы:
-j2
предлагает присоединиться на основе второго столбца каждого файла
-o auto
говорит, что каждая строка должна иметь одинаковый формат, начиная с ключа соединения
-e 0
говорит, что пропущенные значения должны быть заменены нулем
-a 1
и -a 2
включают строки, отсутствующие в том или ином файле
- имена файлов (здесь я использовал имена на основе номера вопроса)
Теперь у нас есть поток вывода в этом формате, мы можем выполнять вычитание в каждой строке. Я использовал эту команду GNU sed для преобразования приведенного выше вывода в программу dc
:
sed -re 's/.*/c&-n[ ]np/e'
Он берет три значения в каждой строке и преобразует их в команду dc
для вычитания, а затем выполняет ее. Например, первая строка становится (с добавлением пробелов для ясности)
c 1009 3 5 -n [ ]n p
который вычитает 5 из 3, печатает его, затем печатает пробел, затем печатает 1009 и новую строку, давая
-2 1009
как требуется.
Затем мы можем передать все эти строки в dc
, что даст нам выходной файл, который мы хотим:
$ join -o auto -j2 -e 0 -a 1 -a 2 41144043-a 41144043-b \
> | sed -e 's/.*/c& -n[ ]np/' \
> | dc
-2 1009
-3 1010
7 1012
1 1013
8 1014
¹ Сортировка должна соответствовать языковому стандарту LC_COLLATE
. Это вряд ли будет проблемой, если поля всегда числовые.
TL;DR
Полная команда:
join -o auto -j2 -e 0 -a 1 -a 2 "$file1" "$file2" | sed -e 's/.*/c& -n[ ]np/' | dc
Он работает построчно и запускает только три процесса, которые вы видите, поэтому он должен быть достаточно эффективным как в памяти, так и в процессоре.
person
Toby Speight
schedule
14.12.2016