Объединение двух файлов списков на основе уникального столбца

#linux #awk #sed

#linux #awk #sed

Вопрос:

У меня есть два файла, один называется NATLog с 3 столбцами, а другой — Sourceports с 2 столбцами, ниже приведен пример файла NATLog.

NATLog

 14 172.18.2.12 445 
50 172.18.24.4 123
80 10.2.123.37 22
68 172.18.1.37 25
  

Я хочу сопоставить последний столбец файла NATLog с первым столбцом файла Sourceports и добавить соответствующую службу в файл NATLog в качестве четвертого столбца

Исходные отчеты

 445 SMB
123 Network Time Protocol (NTP)
22  SSH
25  SMTP(Insecure)
  

Желаемый результат

 14 172.18.2.12 445 SMB 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)
  

Я пытаюсь изучить AWK для достижения этой цели, но мне нужна некоторая помощь, не могли бы вы, пожалуйста, помочь мне, спасибо

Комментарии:

1. Я думаю, что ваш пример неуместен. paste NATLog Sourceports

Ответ №1:

Еще один в awk (ну, на самом деле, два). Это для идеального мира:

 $ awk 'NR==FNR{a[$1]=$0;next}{sub($NF,a[$NF])}1' source natlog
14 172.18.2.12 445 SMB 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)
  

Объяснено (и немного расширено для несовершенного мира):

 $ awk '
NR==FNR {                          # processing the source file
#   gsub(/amp;/,"\\amp;")              # if amp; chars in the file, uncomment to escape them
    a[$1]=$0                       # hash to a, port is the key
    next
}
{                                  # process natlog file
    sub($NF,a[$NF])                # replace port field with entry from source file
#   sub($NF,(a[$NF]?a[$NF]:$NF))   # if gaps in source, use this instead of above
}1' source natlog
  

Один из возможных выходных данных (более короткий ip, amp; символ в исходном коде и непревзойденный порт 222):

 14 1.18.2.12   445 SMB amp; 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 222
68 172.18.1.37 25  SMTP(Insecure)
  

Ответ №2:

Попробуйте awk,

 $ awk ' NR==FNR {x=$1; $1="";a[x]=$0; next } { print $0, a[$3] } ' Sourceports NATLog
14 172.18.2.12 445   SMB
50 172.18.24.4 123  Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

$
  

Ответ №3:

 awk '
    NR==FNR { key=$1; sub(/[^[:space:]] [[:space:]] /,""); map[key]=$0; next }
    { print $0, map[$3] }
' Sourceports NATLog
  

Ответ №4:

Если вашей целью является форматирование выходных данных, отображаемое с добавлением выровненного столбца протокола, то printf вместо print предоставляет тот же самый мелкозернистый элемент управления форматированием, описанный в man 3 printf (по большей части). В вашем случае вам просто нужно получить length() значение поля номер порта и вычесть его из желаемой общей ширины поля, чтобы добавить столько пробелов после записи из NATLog , прежде чем добавлять сохраненный протокол из Sourceports .

Вы могли бы сделать это аналогично следующему, где в качестве примера используется общая ширина поля 4:

 $ awk '
    NR==FNR {pcl[$1] = $2; next} {printf "%s%*s%sn",$0,4-length($3)," ",pcl[$3]}
' Sourceports NATLog
  

Вывод

 14 172.18.2.12 445 SMB
50 172.18.24.4 123 Network
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)
  

(примечание: ваш Sourceports файл не может содержать дополнительных пробелов в конце записей. Если это произойдет, то вам придется заменить $0 на individual $1,$2,$3 и соответствующим образом настроить строку формата)

Обычно существует множество способов выполнить одно и то же в awk , поэтому вы можете адаптировать его к любым вашим потребностям.

Используя paste и awk

Более коротким, но менее эффективным способом было бы использовать оба paste и awk для достижения одной и той же цели. (в основном просто вывод первых двух полей NATLog и добавление содержимого Sourceports с paste помощью, например

 $ paste -d ' ' <(awk '{print $1, $2}' NATLog) Sourceports
14 172.18.2.12 445 SMB
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)
  

(но это действительно помешало бы цели обучения awk )

Ответ №5:

Вот почему в Linux есть куча крошечных инструментов, таких как cat , cut , paste и в этом случае join .

 join -1 3 -2 1 natlog source
  

Объединение работает с файлами, в которых отсортирован столбец, по которому вы пытаетесь join выполнить.

Сортировка на самом деле здесь несколько неправильная формулировка. Это должно быть больше похоже на эквивалентный порядок. Как вы заметили, оба ваших файла имеют одинаковые входные и выходные данные, и столбец, который вы пытаетесь join использовать, эквивалентен. Так join будет работать без проблем.

Если оба файла упорядочены неодинаково, вы могли бы использовать сортировку по нему заранее:

 join -1 3 -2 1 <(sort -k3 natlog) <(sort source)
  

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

 awk '(NR==FNR){k=$3; $3=""; a[k]=$0; next}{ print $0,a[$1] }' natlog source
  

но если natlog и source не имеют одинакового количества строк и / или ключей, то вы получите общую часть в виде

 awk '(NR==FNR){k=$3; $3=""; a[k]=$0; next}($1 in a){ print $0,a[$1] }' natlog source
  

Комментарии:

1. @JamesBrown Я тебя тестировал