Использование «comm» для поиска совпадений между двумя массивами - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть два массива, я пытаюсь найти совпадающие значения, используя comm.Array1 содержит некоторую дополнительную информацию в каждом элементе, которую я вырезал для сравнения.Однако я хотел бы сохранить эту информацию после завершения сравнения.

Например:

Array1=("abc",123,"hello" "def",456,"world")
Array2=("abc")
declare -a Array1
declare -a Array2

Затем я сравниваю два массива:

oldIFS=$IFS IFS=$'\n\t'
array3=($(comm -12 <(echo "${Array1[*]}" | awk -F "," {'print $1'} | sort) <(echo "${Array2[*]}" | sort)))
IFS=$oldIFS

Какойнаходит совпадение abc:

echo ${test3[0]}
abc

Однако я хочу, чтобы оставшиеся значения из массива1 не были частью моего оператора comm.

abc,123,hello

РЕДАКТИРОВАТЬ: для большей ясности

Массивы в этом примере заполнены фиктивными данными.

Мой реальный пример - извлечение информации из журналов сервера, которую я сохраняю в array1.array1 содержит (userIDs, hostIPs, count), которые я хочу сопоставить со списком userID's (array2).Моя цель состоит в том, чтобы выяснить, какие userID существуют в array1 и array2, и сохранить эти идентификаторы с дополнительной информацией из array1 (hostIPs, count) в array3

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

"uniqueID=<ID>","<IP>","<hostname>",1

Я сохраняю результаты отчета spunk как $ splunk, а затем декалярую array1 с результатами $ splunk - информация заголовка, поскольку результаты возвращаются в формате csv

array1=( $(echo $splunk | sed 's/ /\n/g' | sed 1d) )

array2 генерируется из мастер-файла, который я хранил локально.Он содержит все идентификаторы приложений в нашей экосистеме.Например,

uid=<ID>

Я помещаю содержимое мастер-файла в массив2

array2=( $(cat master.txt) )

Затем я хочу найти, какие идентификаторы из массива1 существуют в массиве2, и сохранить его как массив3.Это требует некоторого массива данных в массиве 1, чтобы он соответствовал формату массива 2.

oldIFS=$IFS IFS=$'\n\t'
array3=($(comm -12 <(echo "${array1[*]}" | sed 's/ /\n/g' | awk -F "\"," {'print $1'} | sed 's/\"//g' | sed 's/|/ /g' | awk -F$'=' -v OFS=$'=' '{ $1 = "uid" }1' | grep -i "OU=People" | sed 's/OU/ou/g' | sort) <(echo "${array2[*]}" | sort)))
IFS=$oldIFS

массив 3 будет содержать строки, совпадающие в обоих массивах

uid=<ID>
uid=<ID>

Однако яищу что-то еще по линии

"uid=<ID>","<IP>","<hostname>",1
"uid=<ID>","<IP>","<hostname>",1

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Я бы сделал это так:

join -t, \
    <(printf '%s\n' "${Array1[@]}" | sort -t, -k1,1) \
    <(printf '%s\n' "${Array2[@]}" | sort)

Используйте команду join с , в качестве разделителя полей.Первый «файл» - это первый массив, по одному элементу в строке, отсортированный по первому полю (через запятую);второй «файл» - это второй массив, отсортированный по одному элементу в строке.

Выходными данными будут все строки, в которых первый элемент первого файла соответствует элементу из второго файла;для примера ввода это

abc,123,hello

Это делает только одно предположение, а именно, что ни один элемент массива не содержит символа новой строки.Чтобы сделать его более устойчивым (предполагая GNU Coreutils), мы можем использовать NUL в качестве разделителя:

join -z -t, \
    <(printf '%s\0' "${Array1[@]}" | sort -z -t, -k1,1) \
    <(printf '%s\0' "${Array2[@]}" | sort -z)

Это также печатает выходные данные, разделенные NUL;чтобы прочитать результат в массив, мы можем использовать readarray:

readarray -d '' -t Array3 < <(
    join -z -t, \
        <(printf '%s\0' "${Array1[@]}" | sort -z -t, -k1,1) \
        <(printf '%s\0' "${Array2[@]}" | sort -z)
)

readarray -d требует Bash 4.4 или новее.Для старых Bash вы можете использовать цикл:

while IFS= read -r -d '' element; do
    Array3+=("$element")
done < <(
    join -z -t, \
        <(printf '%s\0' "${Array1[@]}" | sort -z -t, -k1,1) \
        <(printf '%s\0' "${Array2[@]}" | sort -z)
)
0 голосов
/ 25 сентября 2019

Я не знаю, как это сделать с comm, но у меня есть решение для вас с sed и grep.Следующие команды соответствуют регулярному выражению uid=X,, где строка / массив имеет форму uid=x или (uid=x uid=y) соответственно.

# Array 2 (B) is a string
$ A=("uid=1,10.10.10.1,server1,1" "uid=2,10.10.10.2,server2,1")
$ B="uid=1"
$ echo ${A[@]} | grep -oE "([^ ]*${B},[^ ]*)"
uid=1,10.10.10.1,server1,1

# Array 2 (D) is an array
$ C=(${A[@]} "uid=3,10.10.10.3,server3,1" "uid=4,10.10.10.4,server4,1")
$ D=(${B} "uid=3")
$ echo ${C[*]} | grep -oE "([^ ]*($(echo ${D[@]} | sed 's/ /,|/g'))[^ ]*)"
uid=1,10.10.10.1,server1,1
uid=3,10.10.10.3,server3,1

# Content of arrays
$ echo ${A[@]}
uid=1,10.10.10.1,server1,1 uid=2,10.10.10.2,server2,1
$ echo ${B}
uid=1
$ echo ${C[@]}
uid=1,10.10.10.1,server1,1 uid=2,10.10.10.2,server2,1 uid=3,10.10.10.3,server3,1 uid=4,10.10.10.4,server4,1
$ echo ${D[@]}
uid=1 uid=3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...