grep из файла, вывести совпавшие и не совпавшие

У меня есть файл, скажем, input, содержащий шаблоны, как показано ниже:

quantum_mech_.*
astrophysics_.*
geology_.*
economy_*

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

quantum_mech_[101]
astrophysics_[102]
geology_[203]
quantum_mech_[007]
geology_[205]

Я хочу выполнить поиск каждой строки из входного файла и выполнить поиск в файле «тема» и вывести только первое совпадение, а также напечатать «Не сопоставлено», если строка вообще не найдена в файле темы. Итак, я ожидаю вывода, например:

quantum_mech_[101]
astrophysics_[102]
geology_[203]
Not Matched

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

script.csh:

cat $1 | while read line
do grep $line ./subject | head -1 >> output
set VAR=$?
if ( $VAR==0 ) then 
        echo "Not Matched\n" >> output
endif
done

Беги как:

    script.csh input

Любая помощь/указатели, использующие sed/grep/csh, будут отличными.

Спасибо и привет,


person mantu pandey    schedule 05.12.2012    source источник
comment
какую оболочку вы используете? csh? Ваш цикл while имеет неправильный синтаксис для csh.   -  person dogbane    schedule 05.12.2012
comment
да, я использую csh, в котором я не эксперт :( Не могли бы вы исправить код? Спасибо   -  person mantu pandey    schedule 05.12.2012
comment
Не используйте csh для сценариев. Гугл сш почему бы и нет.   -  person Ed Morton    schedule 06.12.2012


Ответы (3)


Это отлично работает в csh и bash.

for line in `cat $1`;
do
  grep -m1 $line ./subject || echo "Not matched"
done >> output

Благодаря указателю Dogbane ниже приведен лучший (и правильный) способ сделать то же самое. Вышеприведенное также имеет проблемы, когда в строках есть пробелы.

while read line 
do
  grep -m1 "$line" ./subject || echo "Not matched"
done < $1 >> output
person Vivek    schedule 06.12.2012
comment
Даже с опубликованным исправлением это не удастся для файлов, содержащих обратную косую черту или имя которых содержит пробелы. Всегда пишите циклы while как while IFS= read -r line и всегда заключайте переменные в кавычки, т. е. "$1", а не $1. - person Ed Morton; 06.12.2012

Это напечатает каждое несопоставленное RE в дополнение к тексту «Not Matched», чтобы вы знали, какие RE не совпали:

$ awk '
NR==FNR{ a[$0]; next }
{ for (re in a) if ($0 ~ re) { print; delete a[re] } }
END{ for (re in a) print re, "Not Matched" }
' file1 file2
quantum_mech_[101]
astrophysics_[102]
geology_[203]
economy_* Not Matched

Он будет работать для любых RE в файле1 и любых значениях в файле2.

person Ed Morton    schedule 06.12.2012
comment
Спасибо за ответ. Но это не дало того же результата, что и при использовании кода Вивека :( в любом случае большое спасибо - person mantu pandey; 06.12.2012
comment
Awk - правильное решение вашей проблемы. Каждый раз, когда вы обнаружите, что пишете цикл в оболочке, вы должны потратить минуту, чтобы пересмотреть то, что вы делаете, поскольку обычно это неправильный подход. Если сценарий, который я разместил, не дает желаемого вывода, то вам стоит потратить время, чтобы рассказать нам, что не так с выводом, чтобы мы могли помочь вам выяснить, что не так с вашими входными файлами или версией awk, которую вы используете. с использованием. - person Ed Morton; 06.12.2012

Вот один из способов использования awk:

awk -F "[.*[]" 'FNR==NR && !($1 in a) { a[$1]=$2 } FNR!=NR { print ($1 in a) ? $1 "[" a[$1] : "Not Matched" }' subjects input

Полученные результаты:

quantum_mech_[101]
astrophysics_[102]
geology_[203]
Not Matched
person Steve    schedule 05.12.2012
comment
слишком долго застрял в моей раковине. (файл большой). но я исправил это через ответ Вивекса, большое спасибо за помощь - person mantu pandey; 06.12.2012