Сравните значения 2 файлов и объедините похожие записи - PullRequest
0 голосов
/ 02 февраля 2020

Я новичок в bash сценариях. У меня есть 2 файла: текстовый файл, содержащий список IP-адресов, файл .csv, который имеет 2 столбца, второй из которых содержит IP-адреса. Я хочу сравнить каждую строку текстового файла (каждый IP-адрес) со всеми элементами 2-го столбца файла .csv. Если в файле .csv есть несколько записей с одним и тем же IP-адресом, я хочу объединить их первые поля подряд. Например:

      column1       column2
row1: example.com   1.1.1.1
row2: example2.com  1.1.1.1

Я хочу преобразовать это в это:

      column1       column2
row1: example.com   1.1.1.1
      example2.com  

Я записал значения в файл .csv и .txt, но я не могу понять, как сравнить и объединить похожие. Я нашел эту команду, но не могу понять, как ее применить:

comm - выбрать или отклонить строки, общие для двух файлов

Ответы [ 4 ]

1 голос
/ 03 февраля 2020

Допущения:

  • CSV-файл (с 2 столбцами: имя домена + IP-адрес) использует запятую (,) в качестве разделителя (это не показано в примерах данных, но ФП упомянул об этом в комментарии)
  • не упоминается о каких-либо требованиях к сортировке окончательного вывода в каком-либо конкретном порядке, поэтому я распечатаю вывод в том же порядке:
    • ips происходят в первом файле
    • адреса доменов встречаются в файле csv
  • образец не был предоставлен для первого файла, поэтому я собираюсь предположить один ip адрес на строку
  • Я не буду беспокоиться о возможности появления IP-адреса более одного раза в первом файле (ie, мы просто будем неоднократно печатать одни и те же доменные имена каждый раз IP-адрес отображается в первом файле)
  • любые записи в любом файле без «соответствия» в другом файле не будут отображаться в конечном выводе

Пример данных:

$ cat domain.dat
example.com,1.1.1.1
example3.com,3.4.5.6
example5.com,11.12.13.14
exampleX.com,99.99.99.99    # no matches in ip.dat
example2.com,1.1.1.1
example4.com,11.12.13.14

$ cat ip.dat
1.1.1.1
2.2.2.2                     # no matches in domain.dat
3.4.5.6
7.8.9.10                    # no matches in domain.dat
11.12.13.14
1.1.1.1                     # repeat of an ip address

Это awk решение начинается с обработки domain.dat для заполнения массива (domains[<ipaddress>]=<domainaddress>[,<domainaddress]*), затем обрабатывается ip.dat для определения того, какие доменные адреса следует печатать на стандартный вывод:

awk -F "," '

# first file: keep track of the longest domain address; to be used by printf

NR==FNR                      { if (length($1) > maxlen) { maxlen=length($1) } }

# first file: if the ip address is already an index in our array then append the current domain address to the array element; skip to next of input

(NR==FNR) && ($2 in domains) { domains[$2]=domains[$2]","$1 ; next }

# first file: first time we have seen this ip address so create a new array element, using the ip address as the array index; skip to next line of input

NR==FNR                      { domains[$2]=$1             ; next}

# second file: if the ip address is an index in our array ...
# split the domain address(es), delimited by comma, into a new array named "arr" ...

( $1 in domains )            { split(domains[$1],arr,",")

                               # set the output line suffix to the ip address

                               sfx=$1

                               # loop through our domain addresses, appending the ip address to the end of the first line; after we print the first domain
                               # address + ip address, reset suffix to the empty string so successive printfs only display the domain address;
                               # the "*" in the format string says to read the numeric format from the input parameters - "maxlen" in this case

                               for (i in arr) { printf "%-*s   %s\n",maxlen,arr[i],sfx ; sfx="" }
                             }
' domain.dat ip.dat

ПРИМЕЧАНИЕ. Встроенные комментарии можно удалить в уменьшить беспорядок.

Результаты выполнения выше:

example.com    1.1.1.1
example2.com
example3.com   3.4.5.6
example5.com   11.12.13.14   # example5.com comes before example4.com in domain.dat
example4.com
example.com    1.1.1.1       # repeated because 1.1.1.1 was repeated in ip.dat
example2.com
0 голосов
/ 02 февраля 2020

Что-то вроде:

    while read IP; do 
       grep $IP subdomainIP.csv | \
           cut -f1 -d',' | \
           tr "\n" " "| \
           sed 's/ $//'; 
       echo ,$IP; 
    done < ipfile.txt
0 голосов
/ 02 февраля 2020

Используя Миллера (https://github.com/johnkerl/miller), начиная с

example.com,1.1.1.1
example2.com,1.1.1.1
example3.com,1.1.1.2

и заканчивая

mlr --csv -N nest --implode --values --across-records -f 1 ipfile.txt >output.txt

, вы получите

example.com;example2.com,1.1.1.1
example3.com,1.1.1.2

Если вы хотите, чтобы URL-адреса разделялись \n, введите команду

mlr --csv -N nest --implode --values --across-records --nested-fs "\n" -f 1 ipfile.txt >output.txt
0 голосов
/ 02 февраля 2020

Вы можете перечислить все IP-адреса, затем l oop поверх IP-адресов, чтобы получить домены, соответствующие этому IP-адресу.

#! /bin/bash
set -euo pipefail

FILENAME="$1"

readarray -t ip_addresses<<<"$(cut -d ',' -f 2 "$FILENAME" | sort -u)"

for ip in "${ip_addresses[@]}" ; do
    readarray -t domains_for_ip<<<"$(grep "$ip" "$FILENAME" | cut -d ',' -f 1)"
    echo "${domains_for_ip[*]},$ip"
done

С входным файлом

example.com,1.1.1.1
example2.com,1.1.1.1
example3.com,1.1.1.2

вы получите

example.com example2.com,1.1.1.1
example3.com,1.1.1.2

Этот сценарий в настоящее время не проверяет наличие первого аргумента ($1) и не может проверить, являются ли IP-адреса действительно уникальными (он будет учитывать 10.0.0.1 и 010.000.000.001 для быть два уникальных адреса). Он также предполагает, что в файле нет странных пробелов.

...