У меня есть два файла - 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
циклы.
Вот один путь в 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
.
попробуйте эту команду:
grep -oFf file1 file2 | grep -vFf - file1
где сначала используют file1 в качестве ШАБЛОНА и получают только часть согласующего отрезка длинной линии, который соответствует ШАБЛОНУ в file2, первая команда дают Вам:
ABC
GHJ
затем используйте этот вывод в качестве входного ШАБЛОНА файла и поисковой строки в file1, который не соответствует ШАБЛОНУ, и Вы доберетесь:
YUI
I8O
Протестированный на Red Hat Enterprise Linux выпуск 4 ES (Обновление Наханта 3)
Использование 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