← Весь справочник

join

Объединить два файла по общему полю, как JOIN в SQL — внутреннее, внешнее, «без пары»

join соединяет строки двух файлов, у которых совпадает значение ключевого поля, — как JOIN в SQL. Например, список id имя и список id роль превращаются в id имя роль. Оба файла должны быть отсортированы по ключу.

Синтаксис

join [опции] файл1 файл2
join -t, -1 2 -2 1 файл1 файл2     # ключ: 2-е поле первого и 1-е поле второго

Один из файлов (но не оба) может быть - — стандартный ввод.

Формат вывода

По умолчанию для каждой пары строк печатается: ключ, затем остальные поля из первого файла, затем остальные поля из второго. Разделитель на выходе — пробел (или символ из -t). Если ключ повторяется в обоих файлах, выводятся все сочетания: 2 строки × 2 строки = 4 строки.

Опции

Ключ и разделитель

ОпцияЧто делает
-1 Nключ в первом файле — поле N (по умолчанию 1)
-2 Nключ во втором файле — поле N
-j Nодно и то же поле в обоих файлах (-1 N -2 N)
-t Cразделитель полей на входе и выходе — один символ (-t,, -t:). Табуляция: -t $'\t'
-iсравнивать ключи без учёта регистра

Без -t поля разделяются пробелами и табуляциями, ведущие пробелы игнорируются, а на выходе ставится одиночный пробел.

Какие строки выводить (типы JOIN)

ОпцияАналог SQLЧто выводится
(без опций)INNER JOINтолько строки, у которых нашлась пара
-a 1LEFT JOINплюс строки первого файла без пары
-a 2RIGHT JOINплюс строки второго файла без пары
-a 1 -a 2FULL JOINплюс непарные из обоих
-v 1анти-joinтолько строки первого файла без пары
-v 2анти-joinтолько строки второго файла без пары

Формат строки

ОпцияЧто делает
-o 1.2,2.3вывести только перечисленные поля: файл.поле; 0 — ключ
-o autoчисло полей берётся по первой строке каждого файла — нужно, чтобы -e заполнял пропуски
-e СТРОКАчем заполнять отсутствующие поля (работает вместе с -o)
--headerпервая строка каждого файла — заголовок: печатается один раз, в паре не участвует

Проверка сортировки

ОпцияЧто делает
--check-orderостановиться с ошибкой на первой неотсортированной строке
--nocheck-orderне проверять (и не предупреждать)
-zстроки разделены нулевым байтом

По умолчанию join предупреждает о беспорядке (is not sorted) только если встретил строку без пары, и тогда возвращает код 1.

Примеры

printf '1 alice\n2 bob\n3 carol\n' > users.txt
printf '1 admin\n3 dev\n4 ops\n' > roles.txt

# inner join по первому полю
join users.txt roles.txt

# left join: bob без роли тоже попадёт
join -a 1 users.txt roles.txt

# full join с заполнителем пропусков
join -a 1 -a 2 -e NULL -o auto users.txt roles.txt

# те, у кого нет роли / роли без пользователя
join -v 1 users.txt roles.txt
join -v 2 users.txt roles.txt

# CSV: ключ — 2-е поле в первом файле и 1-е во втором, вывести имя и роль
printf 'alice,10\nbob,20\n' > people.csv
printf '10,admin\n20,dev\n' > ids.csv
join -t, -1 2 -2 1 -o 1.1,2.2 <(sort -t, -k2,2 people.csv) <(sort -t, -k1,1 ids.csv)

# файлы с заголовком
printf 'id name\n1 alice\n2 bob\n' > hu.txt
printf 'id role\n1 admin\n' > hr.txt
join --header -a 1 -e - -o auto hu.txt hr.txt

# сортировка на лету по ключу
join <(sort -k1,1 users.txt) <(sort -k1,1 roles.txt)

Подводные камни

  • Оба файла сортируй по ключу и как текст. join ожидает тот же порядок, что даёт sort -k1,1 (или sort -t, -kN,N для своего поля) в той же локали. Числовая сортировка не подходит: после sort -n порядок 2, 10 для join — беспорядок, и строки с ключом 10 могут не найти пару и пропасть.
  • Неотсортированный ввод не всегда даёт ошибку. Если все строки случайно нашли пару, предупреждения нет. Если нет — часть строк пропадает, а в stderr появляется input is not in sorted order. В скриптах добавляй --check-order, чтобы падать сразу.
  • Заголовок без --header считается данными. Он участвует в сравнении и в сортировке: sort уберёт строку id name в конец, после цифр, и порядок для join сломается. Либо --header, либо отрежь заголовок (tail -n +2) до сортировки.
  • -e без -o не работает. join -a1 -e NULL выведет короткую строку без заполнителя. Добавь -o auto или явный список полей.
  • -t — только один символ. Многосимвольный разделитель (::, , ) не поддерживается — сначала замени его, например через sed.
  • Без -t выравнивание пробелами теряется: на выходе поля склеиваются одиночным пробелом. Для красивой таблицы пропусти результат через column -t.
  • Регистр и \r важны. Alice ≠ alice (есть -i), а ключ 1\r из Windows-файла не совпадёт с 1.
  • Повторы ключей перемножаются. Две строки с ключом 1 в первом файле и три во втором дадут шесть строк — проверь данные на дубли через uniq -d.

См. также

sort · comm · paste · awk · cut · column