Объедините два файла с awk

File1.txt

item1 carA item2 carB item3 carC item4 platD item5 carE

File2.txt

carA platA carB platB carC platC carE platE

Требуемый вывод:

item1 platA item2 platB item3 platC item4 platD item5 platE

Как я могу это сделать?

9
задан 20 March 2018 в 16:38

4 ответа

Я знаю, что вы сказали awk, но для этой цели есть команда join ...

{ join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) } | sort -k 1

Этого было бы достаточно с первой командой join, если бы это wasn 't для этой строки:

item4 platD

Команда в основном говорит: join на основе второго столбца первого файла (-1 2) и первого столбца второго файла (-2 1) , и выведите первый столбец первого файла и второй столбец второго файла (-o 1.1,2.2). Это только показывает линии, которые соединяются. Вторая команда соединения говорит почти то же самое, но говорит, что она показывает строки из первого файла, который не может быть спарен (-v 1), и выводит первый столбец первого файла, а второй столбец первого файла (-o 1.1,1.2). Затем мы сортируем результат как комбинированных. sort -k 1 означает сортировку на основе первого столбца, а sort -k 2 означает сортировку на основе второго. Важно сортировать файлы на основе столбца объединения, прежде чем передавать их в join.

Теперь я дважды сортировал сортировку, потому что мне не нравятся файлы моих файлов, если я могу помочь Это. Однако, как сказал Дэвид Фостер, в зависимости от размера файлов, вы можете отсортировать файлы и сначала сохранить их, чтобы не ждать, чтобы сортировать их дважды. Чтобы дать представление о размерах, пришло время сортировать 1 миллион и 10 миллионов строк на моем компьютере:

$ ruby -e '(1..1000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 1million.txt $ ruby -e '(1..10000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 10million.txt $ head 10million.txt item530284 plat530284 item7946579 plat7946579 item1521735 plat1521735 item9762844 plat9762844 item2289811 plat2289811 item6878181 plat6878181 item7957075 plat7957075 item2527811 plat2527811 item5940907 plat5940907 item3289494 plat3289494 $ TIMEFORMAT=%E $ time sort 1million.txt >/dev/null 1.547 $ time sort 10million.txt >/dev/null 19.187

Это 1,5 секунды для 1 миллиона строк и 19 секунд для 10 миллионов строк .

6
ответ дан 17 July 2018 в 18:27

Следующий ответ основан на аналогичном Q & amp; A в SO с некоторыми соответствующими изменениями:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt item1 platA item2 platB item3 platC item4 platD item5 platE

Идея состоит в создании хэш-карты с индексом и использовании ее в качестве словаря. [ ! d2]

Для второго вопроса, который вы задали в своем комментарии (что должно быть изменено, если второй столбец file1.txt будет шестым столбцом):

Если входной файл будет как file1b.txt:

item1 A5 B C D carA item2 A4 1 2 3 carB item3 A3 2 3 4 carC item4 A2 4 5 6 platD item5 A1 7 8 9 carE

Следующая команда сделает это:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt item1 platA item2 platB item3 platC item4 platD item5 platE
11
ответ дан 17 July 2018 в 18:27

Я знаю, что вы сказали awk, но для этой цели есть команда join ...

{ join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) } | sort -k 1

Этого было бы достаточно с первой командой join, если бы это wasn 't для этой строки:

item4 platD

Команда в основном говорит: join на основе второго столбца первого файла (-1 2) и первого столбца второго файла (-2 1) , и выведите первый столбец первого файла и второй столбец второго файла (-o 1.1,2.2). Это только показывает линии, которые соединяются. Вторая команда соединения говорит почти то же самое, но говорит, что она показывает строки из первого файла, который не может быть спарен (-v 1), и выводит первый столбец первого файла, а второй столбец первого файла (-o 1.1,1.2). Затем мы сортируем результат как комбинированных. sort -k 1 означает сортировку на основе первого столбца, а sort -k 2 означает сортировку на основе второго. Важно сортировать файлы на основе столбца объединения, прежде чем передавать их в join.

Теперь я дважды сортировал сортировку, потому что мне не нравятся файлы моих файлов, если я могу помочь Это. Однако, как сказал Дэвид Фостер, в зависимости от размера файлов, вы можете отсортировать файлы и сначала сохранить их, чтобы не ждать, чтобы сортировать их дважды. Чтобы дать представление о размерах, пришло время сортировать 1 миллион и 10 миллионов строк на моем компьютере:

$ ruby -e '(1..1000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 1million.txt $ ruby -e '(1..10000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 10million.txt $ head 10million.txt item530284 plat530284 item7946579 plat7946579 item1521735 plat1521735 item9762844 plat9762844 item2289811 plat2289811 item6878181 plat6878181 item7957075 plat7957075 item2527811 plat2527811 item5940907 plat5940907 item3289494 plat3289494 $ TIMEFORMAT=%E $ time sort 1million.txt >/dev/null 1.547 $ time sort 10million.txt >/dev/null 19.187

Это 1,5 секунды для 1 миллиона строк и 19 секунд для 10 миллионов строк .

6
ответ дан 23 July 2018 в 19:15
  • 1
    В этом случае было бы лучше сохранить отсортированные входные данные в (временных) промежуточных файлах, потому что сортировка занимает довольно много времени для нетривиальных наборов данных. Иначе +1. – David Foerster 21 March 2018 в 01:16
  • 2
    @David Это хороший момент. Лично мне очень не нравится создавать промежуточные файлы, но я также нетерпелив от длительных процессов. Я задавался вопросом, что такое «тривиально размер» было бы, и поэтому я сделал небольшой ориентир и добавил его к ответу вместе с вашим предложением. – JoL 21 March 2018 в 05:11
  • 3
    Для сортировки 1 mio-записей достаточно быстро на достаточно современных настольных компьютерах. С еще двумя 3-х порядками все больше становится интересным. В любом случае прошедшее (реальное) время (%E в формате времени) менее интересно измерить вычислительную производительность. Пользовательское время CPU (%U или просто неустановленная переменная TIMEFORMAT) будет гораздо более значимым. – David Foerster 21 March 2018 в 05:47
  • 4
    @David Я не очень хорошо знаком с примерами использования в разные времена. Почему это более интересно? Истекшее время - это то, что совпадает с временем, которое я действительно жду. Для 1,5-секундной команды я получаю 4,5 секунды с %U. – JoL 21 March 2018 в 05:54
  • 5
    Истекшее время зависит от времени, затраченного на ожидание других задач, выполняющихся в одной системе, и блокирования запросов ввода-вывода. (Пользователь) CPU время нет. Обычно при сравнении скорости алгоритмов, связанных с вычислением, нужно игнорировать ввод-вывод и избегать ошибок измерений из-за других фоновых задач. Важным вопросом является «Сколько вычислений требует этот алгоритм для этого набора данных?». вместо «Сколько времени мой компьютер тратил на все свои задачи, пока он ждал завершения этого вычисления? & quot; – David Foerster 21 March 2018 в 06:01

Следующий ответ основан на аналогичном Q & amp; A в SO с некоторыми соответствующими изменениями:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt item1 platA item2 platB item3 platC item4 platD item5 platE

Идея состоит в создании хэш-карты с индексом и использовании ее в качестве словаря. [ ! d2]

Для второго вопроса, который вы задали в своем комментарии (что должно быть изменено, если второй столбец file1.txt будет шестым столбцом):

Если входной файл будет как file1b.txt:

item1 A5 B C D carA item2 A4 1 2 3 carB item3 A3 2 3 4 carC item4 A2 4 5 6 platD item5 A1 7 8 9 carE

Следующая команда сделает это:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt item1 platA item2 platB item3 platC item4 platD item5 platE
11
ответ дан 23 July 2018 в 19:15
  • 1
    @pawana - я обновил свой ответ, чтобы решить второй вопрос в комментарии. Если я ответил на ваш вопрос, пожалуйста, принять это. – Yaron 20 March 2018 в 17:43

Другие вопросы по тегам:

Похожие вопросы: