сравните файл B с A и извлеките данные из A с помощью awk, sed или grep

У меня есть файл с двумя файлами A, который содержит все данные, в то время как есть еще один файл B, у которого есть только те идентификаторы, которые я хочу, чтобы сравнить файл B с файлом A и получить данные, которые присутствуют в этом id. Я использую Suse Linux.

файл A

C 02020 Two-component system [PATH:aap02020] D NT05HA_1798 sensor protein CpxA D NT05HA_1797 CpxR K07662 cpxR C 02030 *Bacterial chemotaxis* [PATH:aap02030] D NT05HA_0919 maltose-binding periplasmic protein D NT05HA_0918 maltose-binding periplasmic protein C 03070 *Bacterial secretion system* [PATH:aap03070] D NT05HA_1309 protein-export membrane protein SecD D NT05HA_1310 protein-export membrane protein SecF D NT05HA_1819 preprotein translocase subunit SecE D NT05HA_1287 protein-export membrane protein C 02060 Phosphotransferase system (PTS) [PATH:aap02060] D NT05HA_0618 phosphoenolpyruvate-protein D NT05HA_0617 phosphocarrier protein HPr D NT05HA_0619 pts system 

файл B

 Bacterial chemotaxis Bacterial secretion system 

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

 C 02030 *Bacterial chemotaxis* [PATH:aap02030] D NT05HA_0919 maltose-binding periplasmic protein D NT05HA_0918 maltose-binding periplasmic protein C 03070 *Bacterial secretion system* [PATH:aap03070] D NT05HA_1309 protein-export membrane protein SecD D NT05HA_1310 protein-export membrane protein SecF D NT05HA_1819 preprotein translocase subunit SecE D NT05HA_1287 protein-export membrane protein 

7 Solutions collect form web for “сравните файл B с A и извлеките данные из A с помощью awk, sed или grep”

Вы можете использовать awk :

 awk 'NR==FNR{ # On the first file, a[$0]; # store the content in the array a next } { # On the second file, for(i in a) # for all element in the array a, if(index($0,i)) { # check if there is match in the current record print "C" $0 # in that case print it with the record separator next } }' fileB RS='\nC' fileA C 02030 *Bacterial chemotaxis* [PATH:aap02030] D NT05HA_0919 maltose-binding periplasmic protein D NT05HA_0918 maltose-binding periplasmic protein C 03070 *Bacterial secretion system* [PATH:aap03070] D NT05HA_1309 protein-export membrane protein SecD D NT05HA_1310 protein-export membrane protein SecF D NT05HA_1819 preprotein translocase subunit SecE D NT05HA_1287 protein-export membrane protein 

Если вы хотите точно соответствовать части, находящейся между C <word> и [PATH:...] (и считая, что эти * в вашем примере предназначены только для акцента, а не для части фактических данных), вы можете сделать :

 awk ' !start {all_strings[$0]; next} /^C/ { key = $0 # strip the leading C <word>: sub(/^C[[:blank:]]+[^[:blank:]]+[[:blank:]]*/, "", key) # strip the trailing [...]: sub(/[[:blank:]]*\[[^]]*][[:blank:]]*$/, "", key) selected = key in all_strings } selected' fileB start=1 fileA 

Помимо дополнительной надежности (например, Bacterial secretion будет соответствовать только для записи Bacterial secretion , а также не для Bacterial secretion system ), она также очень эффективна в том, что файлы считываются только один раз, а совпадение – это только один поиск таблицы хэшей, в отличие от к нескольким подстрокам или регулярным выражениям.

Я уверен, что мне удастся постучать по голове, чтобы использовать петлю, но все же … вот один из способов сделать это.

 #!/bin/bash while read -r line; do sed -n "/$line/,/^C/p" fileA | sed '$d' done < fileB 

Пример:

 ./bacteria.sh C 02030 *Bacterial chemotaxis* [PATH:aap02030] D NT05HA_0919 maltose-binding periplasmic protein D NT05HA_0918 maltose-binding periplasmic protein C 03070 *Bacterial secretion system* [PATH:aap03070] D NT05HA_1309 protein-export membrane protein SecD D NT05HA_1310 protein-export membrane protein SecF D NT05HA_1819 preprotein translocase subunit SecE D NT05HA_1287 protein-export membrane protein 

Где fileA и fileB являются вашими примерами файлов.

Распределение регулярных выражений:

 sed -n "/$line/,/^C/p" fileA | sed '$d' 

Печатайте строки между $line и следующей строкой, начинающейся с буквы C , но исключайте ( sed '$d' ) окончательную строку, так как она используется просто как «маркер остановки».


 sed --version sed (GNU sed) 4.2.2 bash --version GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu) 

С grep и sed в одной строке:

 for i in $(grep -f fileb filea | awk '{print $2}'); do sed -e 's/^C/\nC/g' filea | sed -n "/$i/,/^ *$/p" | grep -v "^$"; done 

То есть:

Возьмите шаблоны для поиска с помощью:

 grep -f fileb filea | awk '{print $2}' 

Вставьте пустую строку перед каждой строкой, начинающейся с C:

 sed -e 's/^C/\nC/g' filea 

Возьмите от рисунка к пустой строке:

 sed -n "/$i/,/^ *$/p" 

Удалите пустые строки, чтобы получить желаемый результат:

 grep -v "^$" 

Все это внутри цикла for, чтобы иметь возможность выполнять один и тот же процесс для каждого шаблона на fileb.

Данные в fileA делятся на записи, начинающиеся с C на новой строке. Каждая запись разделяет inte поля, начинающиеся с D на новой строке.

Нам нужно прочитать строки из fileB и использовать их для запроса первого поля каждой записи в fileA :

 while read -r query; do awk -vq="$query" 'BEGIN { RS="^C|\nC"; FS=OFS="\nD" } $1 ~ q {print "C" $0}' fileA done <fileB 

Я устанавливаю разделитель записи ( RS ) в соответствии с C в начале строки или после новой строки, или мы, возможно, не сможем правильно сопоставить что-либо в первой записи. Я использую переменную awk , q , чтобы сохранить значение, считанное из файла, и я сопоставляю первое поле каждой записи с этим значением.

Результат:

 C 02030 *Bacterial chemotaxis* [PATH:aap02030] D NT05HA_0919 maltose-binding periplasmic protein D NT05HA_0918 maltose-binding periplasmic protein C 03070 *Bacterial secretion system* [PATH:aap03070] D NT05HA_1309 protein-export membrane protein SecD D NT05HA_1310 protein-export membrane protein SecF D NT05HA_1819 preprotein translocase subunit SecE D NT05HA_1287 protein-export membrane protein 

Общее решение, которое охватывает все размеры ваших файлов: https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Grepping-n-lines-for-m-regular-expressions

ПРИМЕР: Грепинг n строк для m регулярных выражений.

Простейшим решением для grep большого файла для большого количества регулярных выражений является:

 grep -f regexps.txt bigfile 

Или если регулярные выражения являются фиксированными строками:

 grep -F -f regexps.txt bigfile 

Существует 3 ограничивающих фактора: процессор, оперативная память и дисковый ввод-вывод.

ОЗУ легко измерить: если процесс grep занимает большую часть свободной памяти (например, при работе сверху), то ОЗУ является ограничивающим фактором.

Процессор также легко измерить: если grep использует> 90% процессор в верхней части, то CPU является ограничивающим фактором, и распараллеливание ускорит это.

Труднее понять, является ли дисковый ввод-вывод лимитирующим фактором, и в зависимости от дисковой системы он может быстрее или медленнее распараллеливаться. Единственный способ узнать наверняка – это проверить и измерить.

Предельный коэффициент: ОЗУ

Обычный файл grep -f regexs.txt работает независимо от размера файла bigfile, но если regexps.txt настолько велик, он не может вписаться в память, тогда вам нужно разделить это.

grep -F занимает около 100 байт оперативной памяти, а grep занимает около 500 байт оперативной памяти за 1 байт регулярного выражения. Так что если regexps.txt составляет 1% от вашей ОЗУ, это может быть слишком большим.

Если вы можете конвертировать ваши регулярные выражения в фиксированные строки, сделайте это. Например, если строки, которые вы ищете в bigfile, выглядят так:

 ID1 foo bar baz Identifier1 quux fubar ID2 foo bar baz Identifier2 

то ваш regexps.txt может быть преобразован из:

 ID1.*Identifier1 ID2.*Identifier2 

в:

 ID1 foo bar baz Identifier1 ID2 foo bar baz Identifier2 

Таким образом, вы можете использовать grep -F, который занимает около 80% меньше памяти и намного быстрее.

Если он по-прежнему не вписывается в память, вы можете сделать это:

 parallel --pipepart -a regexps.txt --block 1M grep -F -f - -n bigfile | sort -un | perl -pe 's/^\d+://' 

1M должна быть вашей свободной памятью, деленной на количество ядер и деленной на 200 для grep -F и на 1000 для обычного grep. В GNU / Linux вы можете:

 free=$(awk '/^((Swap)?Cached|MemFree|Buffers):/ { sum += $2 } END { print sum }' /proc/meminfo) percpu=$((free / 200 / $(parallel --number-of-cores)))k parallel --pipepart -a regexps.txt --block $percpu --compress grep -F -f - -n bigfile | sort -un | perl -pe 's/^\d+://' 

Если вы можете жить с дублированными линиями и неправильным порядком, это быстрее сделать:

 parallel --pipepart -a regexps.txt --block $percpu --compress grep -F -f - bigfile 

Предельный коэффициент: CPU

Если ЦП является ограничивающим фактором, то распараллеливание должно выполняться по регулярным выражениям:

 cat regexp.txt | parallel --pipe -L1000 --round-robin --compress grep -f - -n bigfile | sort -un | perl -pe 's/^\d+://' 

Команда запустит один grep для каждого процессора и прочитает файл bigfile один раз за каждый процессор, но, как это делается параллельно, все чтения, кроме первого, будут кэшироваться в ОЗУ. В зависимости от размера файла regexp.txt может быть быстрее использовать –block 10m вместо -L1000.

Некоторые системы хранения данных работают лучше при одновременном считывании нескольких кусков. Это справедливо для некоторых RAID-систем и для некоторых сетевых файловых систем. Чтобы распараллелить чтение большого файла:

 parallel --pipepart --block 100M -a bigfile -k --compress grep -f regexp.txt 

Это разделит файл bigfile на куски размером 100 Мбайт и запустит grep на каждом из этих фрагментов. Чтобы распараллелить как чтение bigfile, так и regexp.txt, объедините два, используя -fifo:

 parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \ \| parallel --pipe -L1000 --round-robin grep -f - {} 

Если строка соответствует нескольким регулярным выражениям, линия может быть дублирована.

Большая проблема

Если проблема слишком велика, чтобы ее решить, вы, вероятно, готовы к Lucene.

Баш использует только встроенные функции для генерации вывода. Логика кода довольно элементарна и понятна.

удар

 while IFS= read -r line; do IFS=$'\n'; for pat in $(< fileB); do case $line in [C]*"$pat"* ) echo "$line" unset flag break ;; [D]* ) ${flag+":"} echo "$line" ${flag+":"} break ;; * ) flag=;; esac done done < fileA 

С помощью GNU sed мы загружаем шаблоны в область удержания, а затем в данные fileB, мы сравниваем их, чтобы определить, нужно ли печатать блоки C-D + или нет, в зависимости от того, было ли совпадение найдено на линии C, используя шаблоны, хранящиеся в режиме удержания. ФайлB не должен начинаться с C или D.

Sed

 sed -e ' /^D/bD /^C/{ x;G /\n\(.*\)\n\(.*\n\)\{0,1\}[^\n]*\1[^\n]*$/{ s/\(.*\)\n.*/\1/;x :loop n /^C/!bloop s/^/\n/;D } s/\(.*\)\n.*/\1/;x :D $!N;D } H;d ' fileB fileA 

Perl

 perl -l -0777ne ' push(@A, split $\), next if @ARGV; for my $pat ( map { quotemeta } @A ) { while ( /^C [^\n]* $pat [^\n]*$/xmg ) { my $C = $&; print $C .= $& if /\G(\nD.*$)+/xm; } } ' fileB fileA 
  • Как печатать строки, соответствующие шаблону с помощью grep?
  • Как определить файлы формата dos в git bash
  • Скрипт для поиска трех разных пользователей в Интернете и печати
  • Выход grep cdrecord
  • Почему «grep». * «файл» работает и «grep. * файл« нет »?
  • Попытка grep url из источника html в .txt-файле с помощью sed
  • Может ли кто-нибудь объяснить это выражение по частям, пожалуйста? grep '\ ( \). \ 1'
  • Извлеките две строки после строки с определенным значением
  • условная окраска в grep
  • Удалить файлы с совпадением только из некоторых подкаталогов
  • grep --color добавляет код ANSI ESC [K - это может изменить отображаемый текст
  • Interesting Posts

    Загрузите список файлов, если они еще не существуют.

    Чтение разрешений на чтение запрещено, несмотря на наличие достаточных разрешений

    В awk, как я могу сделать логическое значение, которое я могу переключить?

    Как я могу определить, какой IP-адрес используется для подключения к другому компьютеру?

    Как я могу найти допустимые значения для TERM для использования в tmux?

    Как копировать только файлы папки (включая файлы вложенных папок), но не сама папка в оболочке

    Как сделать экран черно-белым?

    Заменить строку, содержащую символы новой строки

    Изменить временную метку файла и время показа вместо года с помощью ls

    С чего начать изучать OpenGL

    Как условия гонки влияют на чтение и запись (которые происходят одновременно)

    sudo не распознает новую группу

    Уязвимость OpenSSL Padding для Oracle (CVE-2016-2107) + Nginx

    Как обрабатывать повторяющиеся загрузки некоторых конкретных больших файлов, которые поступают из Интернета

    терминал висит, когда потерянное соединение и ssh включено

    Linux и Unix - лучшая ОС в мире.