Найти только те идентификаторы из списка, которые присутствуют в обоих из двух файлов данных - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть текстовый файл IDs.txt, содержащий одну строку уникального идентификатора в строке, например:

foo
bar
someOtherID

Я знаю, что некоторые из этих идентификаторов находятся в один илиоба из 2 других файлов с различными форматами строк данных, 1.txt и 2.txt

1.txt
id=foo
name=example
age=81
end
id=notTheIDYouAreLookingFor
name=other
age=null
2.txt
<Data>
<ID>foo</ID>
<Stuff>Some things</Stuff>
</Data>
<Data>
<ID>bar</ID>
<Stuff>Other things</Stuff>
</Data>

Конкретные форматы данных не важны, так как все, что мне нужно ответить, это «какие идентификаторы»в обоих? ", и действительно в идеале мне нужно решение, не зависящее от формата

В примере я хочу найти строки с foo:

<ID>foo</ID> id=foo

Фактически: этот вопрос , но с большим списком идентификаторов против 2 файлов вместо 1 и поиском общих совпадений.

Ответы [ 3 ]

0 голосов
/ 25 февраля 2019

Вот один для GNU awk, далеко не идеальный:

$ awk '
NR==FNR {                                      # store file1 entries to a[1]
    a[ARGIND][$0]
    next
}
match($0,/([iI][dD][>=])([^<]+)/,arr) {        # hash on whats =after or >between<
    a[ARGIND][arr[2]]=$0                       # store whole record. key on above
}
END {
    for(i in a[1])                             # get keywords from first file
        if((i in a[2]) && (i in a[3]))         # if found in files 2 and 3
            print a[2][i],a[3][i]              # output
}' file1 file2 file3

Вывод:

id=foo <ID>foo</ID>
0 голосов
/ 26 февраля 2019

Я не awk эксперт, поэтому я склонен разбивать вещи на куски, когда это может сделать одна строка.

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

$ cat << EOF > work.sh
#!/usr/bin/env bash

# 1.txt has IDs in the form id=....

grep -x 'id=.*' 1.txt | sed -e 's/^id=//' | sort > 1.txt.ids

# 2.txt has IDs in the form <ID>...</ID>

grep -x '^<ID>.*</ID>' 2.txt | sed -Ee 's-^<ID>(.*)</ID>-\1-' | sort > 2.txt.ids

comm -12 1.txt.ids 2.txt.ids  | grep -xf IDs.txt
EOF

Первая команда grep извлекает строки из 1.txt, которые полностью состоят из 'id = кое-что', затем удаляет 'id =' и сортирует их в файл 1.txt.ids.

Второй grep делает то же самое для строк из 2.txt, которые полностью состоят из ' что-то ', затем удаляет открытые и закрывающие теги ID и сортирует идентификаторы в 2.txt.ids.

comm используется для отображения только строк, которые появляются в обоих файлах, ивывод comm дополнительно фильтруется IDs.txt, который представляет собой список конкретных идентификаторов, которые вас интересуют.

$ cat 1.txt  
id=foo
name=example
age=81
end
id=notTheIDYouAreLookingFor
name=other
age=null
$ cat 2.txt
<Data>
<ID>foo</ID>
<Stuff>Some things</Stuff>
</Data>
<Data>
<ID>bar</ID>
<Stuff>Other things</Stuff>
</Data>
$ cat IDs.txt
foo
bar
someOtherID
$ bash work.sh
foo
0 голосов
/ 25 февраля 2019

Поскольку вы просто хотите узнать идентификаторы в обоих файлах (f1 и f2), вам не нужно анализировать ids.txt:

awk 'NR==FNR{a["<ID>"$1"</ID>"]="id="$1;next}
    a[$0]{print $0,a[$0]}' <(grep -oP 'id=\K.*' f1) f2

вышеприведенных однострочных выходов:

<ID>foo</ID> id=foo
...