Обработка 2 файлов с разными разделителями полей с помощью awk

Допустим, у меня есть 2 файла:

$ cat file1
A:10
B:5
C:12

$ cat file2
100 A
50 B
42 C

Я хотел бы иметь что-то вроде:

A 10 100
B 5 50
C 12 42

Я пробовал это:

awk 'BEGIN{FS=":"}NR==FNR{a[$1]=$2;next}{FS=" ";print $2,a[$2],$1}' file1 file2

Что выводит меня, что:

  100 A
B 5 50
C 12 42

Я предполагаю, что проблема связана с разделителем полей, который установлен слишком поздно для второго файла. Как я могу установить разные разделители полей для разных файлов (а не для одного файла)?

Спасибо


Изменить: более общий случай

С файлом2 и файлом3 вот так:

$ cat file3
A:10 foo
B:5 bar 
C:12 baz

Как получить :

A 10 foo 100
B 5 bar 50
C 12 baz 42

awk
person jrjc    schedule 01.07.2014    source источник
comment
Один вариант, не обязательно лучший, состоит в том, чтобы предварительно обработать один из файлов, чтобы он имел тот же разделитель, что и другой, а затем обработать их «естественно» с одним разделителем.   -  person Jonathan Leffler    schedule 01.07.2014
comment
Возможный дубликат множественного разделителя AWK   -  person jww    schedule 16.08.2018
comment
@jww Это не так. Этот вопрос о том, как иметь разные разделители для разных файлов (а не для одного файла), и ответ другой.   -  person jrjc    schedule 16.08.2018


Ответы (3)


Просто установите FS между файлами:

awk '...' FS=":" file1 FS=" " file2

i.e.:

$ awk 'NR==FNR{a[$1]=$2;next}{print $2,a[$2],$1}' FS=":" file1 FS=" " file2
A 10 100
B 5 50
C 12 42
person Ed Morton    schedule 01.07.2014
comment
ааа прикольно, это то что я искал! - person jrjc; 01.07.2014
comment
Да, это то, для чего задаются переменные в списке файлов - заполнение начальных значений по-разному для разных файлов. Для всего остального лучше установить их заранее, используя -v. - person Ed Morton; 01.07.2014
comment
не понимал, что FS можно использовать вместо -F, как это - person jimh; 21.03.2016

Вам нужно заставить awk повторно разделить $0 после изменения FS.

Вы можете сделать это с помощью $0=$0 (например).

Итак, {FS=" ";$0=$0;...} в вашем последнем блоке будет делать то, что вы хотите.

Хотя делать это только в первый раз, когда вам нужно изменить FS, вероятно, будет немного лучше работать с большими файлами.

person Etan Reisner    schedule 01.07.2014
comment
@jeanrjc Здесь это сработало. Какую версию awk вы используете? Выход изменился вообще, когда вы это сделали? - person Etan Reisner; 01.07.2014
comment
Ничего не изменилось. Я использую BSD-версию awk (пользователь Mac) - person jrjc; 01.07.2014
comment
@jeanrjc Вы запустили awk 'BEGIN{FS=":"}NR==FNR{a[$1]=$2;next}{FS=" ";$0=$0;print $2,a[$2],$1}' file1 file2 и все еще получили исходный результат? - person Etan Reisner; 01.07.2014
comment
да ! (скопировал то, что вы написали, результат тот же) - person jrjc; 01.07.2014
comment
Это странно. Вы можете попробовать сохранить $1, установить для него что-то другое, а затем вернуть сохраненное значение. Это может привести к повторному разделению, чего не сделает $0=$0, но я не знаю. Вы также можете попробовать $1=$1 вместо $0=$0 и посмотреть, сработает ли это. - person Etan Reisner; 01.07.2014
comment
Даже не пытайтесь использовать $1=$1, так как это перекомпилирует текущую запись, используя значение OFS, а не FS. Назначение $0=$0 ЯВЛЯЕТСЯ правильным способом повторного разделения записи с использованием текущего значения FS. Если это не сработает для OP, то его awk не работает. - person Ed Morton; 01.07.2014
comment
@EdMorton Спасибо за исправление $1=$1. Также для подтверждения того, что $0=$0 должен работать (даже в BSD awk). - person Etan Reisner; 02.07.2014
comment
@EdMorton: Это странно. Я попробовал на другом компьютере (все еще Mac), и он все еще не работает. Работает ли это на компьютере Mac для вас? - person jrjc; 02.07.2014
comment
У меня нет Мака. Стандартный awk на Mac не работает по-другому, так что, может быть, он тоже не работает? - person Ed Morton; 02.07.2014

person    schedule
comment
2 in a не совпадает с его оригинальным сценарием. Он пропустит вывод, который был бы произведен оригиналом, когда file2 содержит строки, которых нет в file1. - person Etan Reisner; 01.07.2014
comment
@EtanReisner Это правильно, но часто это правильный путь, когда используются такие реализации. ОП не уточнил, хочет ли он сохранить реплики или нет, но я ценю ваши отзывы, поскольку они могут помочь ОП принять решение либо оставить их, либо удалить, как он считает нужным. - person jaypal singh; 01.07.2014
comment
Я не уверен, что понял, что вы имели в виду, но оба файла имеют одинаковые ключи (A,B,C). With the multiple field sperator, won't it be a problem if there is :` во втором файле? - person jrjc; 01.07.2014
comment
@jeanrjc Да, будет проблема. В ваших примерах данных вы, кажется, не ясно указываете, что несколько разделителей полей присутствуют в обоих файлах. Я бы порекомендовал вам добавить некоторые образцы данных, которые действительно представляют ваши файлы. - person jaypal singh; 01.07.2014
comment
Хорошо, а можешь объяснить $2 in a ? - person jrjc; 01.07.2014
comment
@jeanrjc Это проверяет, находится ли значение $2 в массиве a, а затем выводит строку только в том случае, если это правда. Итак, как я указал в своем первом комментарии, он будет печатать строки из file2 только тогда, когда их второе поле также появилось в первом поле file1. - person Etan Reisner; 01.07.2014
comment
разделенное решение отлично работает с моими реальными данными, файл3 был больше, потому что я хотел более общее решение. - person jrjc; 01.07.2014
comment
@jeanrjc Сохранить $0 в массиве a, а затем распечатать $0 a[t[2]] во втором блоке? - person Etan Reisner; 01.07.2014