удалить строки, содержащие строки из другого файла по указанному индексу - PullRequest
0 голосов
/ 04 июня 2019

У меня есть файл с именем main_file с переменным количеством столбцов.Первые два столбца main_file всегда имеют одинаковое количество символов и одинаковый разделитель полей, а затем появляется различная информация.Информация в остальной части строки может быть чем угодно, включая те же, что и в первых столбцах, поэтому я не могу просто выполнить поиск строки.Строки также не обязательно уникальны.

 aaaa  A --------- fdsfadf 
 aaaa  B --------- fasdfa
 bbbb  A --------- hgfhf
 bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 cccc  A --------- sdfsa      mjhhfdgdf
 cccc  B --------- werwfds     fsa wrew
 cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
 aaaa  B --------- fasdfa erwrew

У меня есть файл с именем code_list, который содержит все записи, которые необходимо удалить из файла.

aaaa  A
aaaa  B
bbbb  A
bbbb  B
cccc  A
cccc  B
cccc  P

Я хотел быудалить или закомментировать из main_file все строки, в которых есть записи из code_list

Так что я хотел бы получить (в том же порядке):

* aaaa  A --------- fdsfadf 
* aaaa  B --------- fasdfa
* bbbb  A --------- hgfhf
* bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
* cccc  A --------- sdfsa      mjhhfdgdf
* cccc  B --------- werwfds     fsa wrew
* cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
* aaaa  B --------- fasdfa erwrew

или получить:

 1ulm  A --------- tret utrtry
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    lkjl
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

Я пытался запустить myscript.sh code_list

, где myscript.sh:

#!/bin/bash

while IFS='' read -r line || [[ -n "$line" ]]; do


    awk '{if(substr($0,2,7) == "'$line'") {print "*"$0}else{print $0}}' main_file > out


done < "$1"

, но я получаю сообщение об ошибке "неопределенная строка", когда я пытался

awk '{if(substr($0,2,7) == "aaaa  A") {print "*"$0}else{print $0}}' main_file > out

тогда все работает.Но файл code_list слишком длинный, чтобы я мог писать вручную каждое имя, и я не смог установить его как переменную.

Каков наилучший способ удалить или закомментировать эти строки

Ответы [ 4 ]

2 голосов
/ 04 июня 2019
$ awk '{k=$1 FS $2} NR==FNR{a[k]; next} !(k in a)' code_list main_file
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

$ awk '{k=$1 FS $2} NR==FNR{a[k]; next} {print (k in a ? "*" : "") $0}' code_list main_file
* aaaa  A --------- fdsfadf
* aaaa  B --------- fasdfa
* bbbb  A --------- hgfhf
* bbbb  B --------- hftret jhtruyr
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
* cccc  A --------- sdfsa      mjhhfdgdf
* cccc  B --------- werwfds     fsa wrew
* cccc  P --------- fsda   wrewr
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
* aaaa  B --------- fasdfa erwrew
2 голосов
/ 04 июня 2019

Один из них мой:

awk 'NR==FNR {a[$0]++;next} {b=substr($0,2,7)} !(b in a)' filter data
awk 'NR==FNR {a[$0]++;next} !(($1"  "$2) in a)' filter data
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
2 голосов
/ 04 июня 2019

Здесь вы можете использовать технику NR == FNR, чтобы awk позаботился об обработке обоих файлов.Когда NR == FNR означает, что номер обрабатываемой записи совпадает с номером записи в текущем файле, другими словами, вы обрабатываете первый файл в списке аргументов (в данном случае code_list).

Связанное действие для первого файла состоит в создании таблицы поиска для обработки второго файла (main_file).

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

 $ awk 'NR == FNR {a[$1 FS $2]; next} !(($1 FS $2) in a)' code_list main_file 
 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw
1 голос
/ 04 июня 2019

Предлагаю преобразовать данные в файле code_list в шаблоны для grep, привязанные к началу строки

sed 's/^/^/' code_list > code_list2

Редактировать: Это будет работать, если code_list и main_file содержат одинаковые начальные пробелы.

Предполагая, что файл code_list содержит ровно один начальный пробел, результирующий файл code_list2 будет содержать

^ aaaa  A
^ aaaa  B
^ bbbb  A
^ bbbb  B
^ cccc  A
^ cccc  B
^ cccc  P

Если начальные пробелы могут отличаться (или отсутствовать), замена может быть расширена:

sed 's/^ */^ */' code_list > code_list2

Это удаляет любое количество начальных пробелов и добавляет шаблон для любого количества ведущих пробелов. Обработка вкладок также потребует дополнительных изменений.

Полученный файл code_list2 будет содержать

^ *aaaa  A
^ *aaaa  B
^ *bbbb  A
^ *bbbb  B
^ *cccc  A
^ *cccc  B
^ *cccc  P

(конец редактирования)

Затем используйте это, чтобы извлечь строки, которые не соответствуют

grep -v -f code_list2 main_file

С этим я получаю

 1ulm  A --------- tret aaaa  A
 1ulm  X --------- fsdfs fdsfs
 1ulm  B --------- yttertre   ertre
 ghh1  A --------- rwerw     wrew
 ghh1  G --------- werwe    bbbb  B
 ghh2  A --------- Pewrew   trerew rwew
 ghh2  G --------- fdss         rewrw8
 ghh4  A --------- qweqe          321313
 ghh4  G --------- 3242   wrewrw

Если вы используете оболочку, которая поддерживает <( command ), например, bash, вы можете объединить две команды как

grep -v -f <(sed 's/^/^/' code_list) main_file

Редактировать: или обрабатывать различные начальные пробелы

grep -v -f <(sed 's/^ */^ */' code_list) main_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...