Получите Не соответствующую строку от file1 до file2

У меня есть два файла - file1 и file2.

file1 содержит (только слова):

ABC 
YUI 
GHJ 
I8O

file2 содержит много абзацев:

dfghjo ABC kll 
njjgg bla bla GHJ 
njhjckhv chasjvackvh .. 
ihbjhi hbhibb jh jbiibi 

Я использую команду ниже для получения согласующих отрезков длинной линии, который содержит слово от file1 в file2:

grep -Ff file1 file2 

(Дает вывод строк где слова file1 найденный в file2)

Мне также нужны слова от file1 которые не найдены в file2.

Может любой помогать в получении этого вывода:

YUI 
I8O

Я ищу одну команду лайнера (через grep, awk, sed), поскольку я использую pssh управляйте и не может использовать while или for циклы.

1
задан 19 February 2019 в 12:23

3 ответа

Вот один путь в awk:

$ awk 'NR==FNR{a[$1]++; next}{for(i in a){if($0 ~ i){found[i]++}}}END{for(i in a){if(!found[i]){print i}}}' file1 file2 
YUI
I8O

Или, немного более четко:

$ awk 'NR==FNR{
        a[$1]++; 
        next
       }
       {
        for(i in a){
            if($0 ~ i){
                found[i]++
            }
        }
       }
       END{
        for(i in a){
            if(!found[i]){
                print i
            }
        }
       }' file1 file2 
YUI
I8O

Объяснение

  • NR==FNR : NR текущий номер строки и FNR текущий номер строки текущего файла. При обработке нескольких файлов эти два будут равны только при чтении первого файла. Таким образом, это - простой способ сказать, "делают это для 1-го файла только".
  • a[$1]++; next : при чтении первого файла сохраните каждое слово (первое и единственное поле) в массиве a и затем пропустите к следующей строке. next также гарантирует, что остальная часть команды не выполняется для первого файла.
  • for(i in a){ if($0 ~ i){ found[i]++ } }: Для каждого из слов, найденных в первом файле (ключи массива a), проверьте, распознает ли текущая строка то слово. Если это делает, сохраните слово в found массив. Это выполняется для каждой строки второго входного файла.
  • END{ }: сделайте это после обработки всех входных файлов.
  • for(i in a){ if(!found[i]){ print i } }: для каждого из слов в a, если слово не находится также в found массив, распечатайте то слово.

С другой стороны, можно использовать некоторые базовые утилиты Linux:

$ grep -hoP '\w+' file1 file2 | sort | uniq -u | xargs -I{} grep {} file1
I8O
YUI 

Объяснение

$ grep -hoP '\w+' file1 file2
ABC
YUI
GHJ
I8O
dfghjo
ABC
kll
njjgg
bla
bla
GHJ
njhjckhv
chasjvackvh
ihbjhi
hbhibb
jh
jbiibi

Это распечатает все слова, найденные в каждом файле. -o флаг означает, "только печатают часть соответствия строки", -P включает Perl совместимые регулярные выражения (PCRE), которые позволяют нам использовать \w означать "любой словесный символ" (так буквы, числа, _).

$ grep -hoP '\w+' file1 file2 | sort | uniq -u
chasjvackvh
dfghjo
hbhibb
I8O
ihbjhi
jbiibi
jh
kll
njhjckhv
njjgg
YUI

Теперь мы передаем вывод предыдущей команды через sort и uniq -u сохранять только уникальные соответствия: это слова, которые только присутствуют в одном из этих двух файлов.

$ grep -hoP '\w+' file1 file2 | sort | uniq -u | xargs -I{} grep {} file1
I8O
YUI 

Наконец, мы подаем этот список уникальных слов к xargs и имейте его grep каждый из них в file1. Только те уникальные слова, которые присутствуют в file1 будет возвращен, и уникальные слова, существующие в file1 поэтому не существуют в file2.

1
ответ дан 7 December 2019 в 15:07

попробуйте эту команду:

grep -oFf file1 file2 | grep -vFf - file1

где сначала используют file1 в качестве ШАБЛОНА и получают только часть согласующего отрезка длинной линии, который соответствует ШАБЛОНУ в file2, первая команда дают Вам:

ABC
GHJ

затем используйте этот вывод в качестве входного ШАБЛОНА файла и поисковой строки в file1, который не соответствует ШАБЛОНУ, и Вы доберетесь:

YUI
I8O

Протестированный на Red Hat Enterprise Linux выпуск 4 ES (Обновление Наханта 3)

0
ответ дан 7 December 2019 в 15:07

Использование Perl:

Основной алгоритм + эквивалентный Perl:

slurp f2                              // $f2 = `cat f2`
for all lines in f1                   // perl -nle  '....' f1
   print if f2 does not have it       //    print  if $f2 !~ /$_/

Все вместе:

perl -nle 'BEGIN {$f2=`cat f2`}  
           print  if $f2 !~ /$_/'  f1
0
ответ дан 7 December 2019 в 15:07

Другие вопросы по тегам:

Похожие вопросы: