2015-01-15 4 views
3

Существует три файла с столбцами, разделитель - «|», столбцы в строках могут быть пустыми. Мне нужно присоединиться к второму и третьему файлам, чтобы сначала использовать столбцы 3 и 4 в первом файле, а столбец 1 - во втором и третьем.Bash - объединение (слияние) файлов по столбцам

Например:

file1.txt:

123456||4|11|17|A||10|B|1 
123457||4|11|17|A||12||1 
123458||5|11|17|A||1|Б|1 
123459||6|13|17|A||1|Б|1 

file2.txt:

4|Forth 
5|Fifth 
6|Sixth 

file3.txt:

11|st.|Eleventh 
13|pr.|Thirteenth 

Какой же выход я желаю:

123456||4|Forth|11|st.|Eleventh|17|A||10|B|1 
123457||4|Forth|11|st.|Eleventh|17|A||12||1 
123458||5|Fifth|11|st.|Eleventh|17|A||1|Б|1 
123459||6|Sixth|13|pr.|Thirteenth|17|A||1|Б|1 

Как написать сценарий Bash, который будет делать то, что мне нужно? Я понимаю, что это команда awt, но я не мог написать сценарий. Спасибо за ответы.

ответ

4

Вы можете использовать эту команду AWK:

awk 'BEGIN{ FS=OFS="|" } 
    NR == FNR {a[$1]=$0; next} 
    NR == FNR + length(a) {b[$1]=$0; next} 
    {$3=b[$3]; $4=a[$4]} 1' file3.txt file2.txt file1.txt 
123456||4|Forth|11|st.|Eleventh|17|A||10|B|1 
123457||4|Forth|11|st.|Eleventh|17|A||12||1 
123458||5|Fifth|11|st.|Eleventh|17|A||1|Б|1 
123459||6|Sixth|13|pr.|Thirteenth|17|A||1|Б|1 

Объяснение:

  • BEGIN{ FS=OFS="|" } - Установить входные и выходные разделители полей в трубе |
  • NR == FNR - Выполнить этот блок для первого файла только
  • a[$1]=$0; next - Создайте Массив a с ключом как $1 и значением, как полная линия
  • NR == FNR + length(a) - Выполнить этот блок для второго файла только
  • b[$1]=$0; next - Создать массив b с ключом, как $1 и значение в полной линии
  • Выполнить следующий блок {...} для последний (третий) файл
  • $3=b[$3]; - Присвоить значение b[$3] на 3-е поле
  • $4=a[$4]; - Присвоить значение a[$4] на 4-е поле
  • 1 - это действие по умолчанию для печати каждой записи
+2

Отлично, спасибо вам большое! –

+0

Добро пожаловать, рад, что это сработало. – anubhava

+1

Well @anubhava Я становлюсь вашим поклонником, этот ответ - отличный ответ, точно похоже на операцию соединения SQL. Я изучаю много ответов. – Skynet

1

Здесь:

#!/bin/bash 

while IFS='|' read c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 
     do 
     st1=$(fgrep "$c3" file2.txt) 
     st2=$(fgrep "$c4" file3.txt) 
     echo "$c1|$c2|$st1|$st2|$c5|$c6|$c7|$c8|$c9|$c10" 
     done 
2

Предполагая, что файлы сортируются:

join -t'|' -1 4 -2 1 \ 
    <(join -t '|' -1 3 -2 1 file1.txt file2.txt) file3.txt 

Если вам действительно нужны поля в конкретном порядке добавьте опцию выходного формата:

-o1.2,1.3,1.1,1.11,1.4,2.2,2.3,1.5,1.6,1.7,1.8,1.9,1.10,1.11 
Смежные вопросы