Переформатируйте исходный пример для удобства чтения:
join -a1 -e "NoMatch" \
<(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) \
<(cat file2 | sort -k1,1)
Все проблемы связаны с обработкой file2 и с опциями join
.
-t ''
для join
, файл2 разделен табуляцией. join
для объединения по полю 2 файла2. join
для файла2, вывод по умолчанию печатает сначала поле join, поэтому необходимо указать опцию -o FORMAT
на join
. tail
не нужен в файле1, потому что awk
может пропустить первую строку. -F ' '
для awk
. Исправление этих проблем дает следующее:
#!/bin/bash
head -1 file2
join -t ' ' -2 2 -a 1 -e NoMatch -o 2.1,2.2,2.3 \
<(awk 'NR==1{next} {print $0}' file1.txt | sort) \
<(tail -n +2 file2 | sort -k2)
Что дает следующий вывод с разделителями табуляции:
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
NoMatch NoMatch NoMatch
1 d aaaa4
Один из способов переноса такого рода вещей заключается в следующем:
sed -e '
#... assuming prev sed cmds made pattern space carry newline(s)
y/\n_/_\n/ ;# exchange newlines with an underscore
s/^[^_]*_// ;# remove up till the first underscore, ummm newline
y/\n_/_\n/ ;# revert the transformation
'
Глупо, но работает:
sed 'h;G;s/\n/&&/;s/^\(.*\)\n\(.*\)\n\1\2$/\2/'
Что это? Вы удваиваете весь контент, затем заменяете первую новую строку двумя новыми строками. Таким образом, у вас есть один и тот же контент дважды с одной дополнительной новой строкой после первой строки. Теперь с помощью обратных ссылок вы можете идентифицировать различные части.
Если вы не хотите использовать буфер удержания:
sed 's/.*/&&/;s/\n/&&/;s/^\(.*\)\n\(.*\)\1\2$/\2/'
И нет, мне это не нравится. Если есть способ избежать этого, избегайте его.