Как объединить значения из двух разных текстовых файлов?

2

У меня есть следующие данные в текстовых файлах:

file1.txt

a1:b1
a2:b2
a3:b3
a4:b4
a5:b5

file2.txt

b2:c1
b4:c2
b5:c3

Как объединить эти значения, чтобы сделать выходной файл следующим образом:

output.txt

a2:c1
a4:c2
a5:c3
    
задан summertime-sadness 30.07.2015 в 19:37
источник

2 ответа

5

Поскольку ваши файлы содержат отсортированные данные, вы должны иметь возможность использовать команду join , например.

join -12 -21 -t: -o1.1,2.2 file1.txt file2.txt > output.txt

Тогда

cat output.txt
a2:c1
a4:c2
a5:c3

Подробнее о параметрах см. в man join .

Если файлы не предварительно отсортированы, вы можете отсортировать их сначала с помощью замены процесса. Обратите внимание, что сортировка должна находиться в поле, в которое вы хотите присоединиться к файлам , например.

join -12 -21 -t: -o1.1,2.2 <(sort -t: -k2,2 file1.txt) <(sort -k1,1 file2.txt)
androgynous:hu2nt
gra7vel:fi6nal
cosm4etic:citizen

Результат также будет в отсортированном порядке: если вы этого не хотите, тогда существует довольно стандартный способ сделать это в awk , используя массив, например.

awk -F: 'NR==FNR {a[$2]=$1; next;} ($1 in a) {print a[$1]":"$2;}' file1.txt file2.txt
    
ответ дан steeldriver 30.07.2015 в 19:42
источник
5

Вот подход awk :

awk -F: '(NR==FNR){a[$2]=$1; next}($1 in a){print a[$1]":"$2};' file1 file2 > out

Объяснение

  • awk -F: Запустить awk , установив разделитель полей в : . Это будет читать каждую строку ввода и разделить ее на : . Итак, для первой строки file1 первое поле ( $1 ) - a1 , а второе ( $2 ) - b1 .
  • (NR==FNR){} : Если NR равно FNR . NR - текущий номер строки ввода, а FNR - номер строки текущего файла. Эти два будут равны только при чтении первого файла.
  • a[$2]=$1; next : сохранить второе поле как ключ в массиве a , значение которого является 1-м полем. Затем перейдите к следующей строке.
  • ($1 in a){print a[$1]":"$2} : это будет выполняться только при чтении второго файла. Если первым полем второго файла является массив ключей a , напечатайте значение для этого ключа (второе поле соответствующей строки из file1 ).

И один Perl:

perl -F: -lanE '$k{$F[0]} ? say "$k{$F[0]}:$F[1]" : ($k{$F[1]}=$F[0]);' file1 file2 > out

Или, если вы предпочитаете:

perl -F: -lanE '$k{$F[0]} and say "$k{$F[0]}:$F[1]" or ($k{$F[1]}=$F[0]);' file1 file2 

Объяснение

  • perl -F: -lanE : -n означает «читать каждый входной файл по строкам и применять скрипт, заданный -E для каждого из них». -E , например -e , позволяет передать сценарий в командной строке. Разница в том, что -E позволяет использовать некоторые дополнительные функции, такие как say . -a позволяет автоматическое разбиение каждой строки ввода на символ, заданный -F . Вместе они делают perl , как awk . Поля разбиты на массив @F , а первое поле - $F[0] , второе $F[1] и т. Д. Наконец, -l переводит символы новой строки ( \n ) из конца каждой строки.
  • $k{$F[0]} ? foo : bar : Если определена переменная $k{$F[0]} , сделайте foo, иначе сделайте bar.
  • ($k{$F[1]}=$F[0]) : это происходит, если $k{$F[0]} не определено (это «бар», выше). Он сохранит второе поле как ключ в хеш %k , значение которого является 1-м полем.
  • say "$k{$F[0]}:$F[1]" : это будет выполняться, если определено $k{$F[0]} («foo» выше), поэтому, если 1-е поле текущей строки было вторым полем в другой строке. Если это так, print ( say похоже на print , но добавляет новую строку) 1-ое поле текущего и связанное с ним значение в хеше.
ответ дан terdon 31.07.2015 в 00:20