Как найти строки, содержащие строку, а затем напечатать эти конкретные строки и что-то еще

Я использую следующую команду для рекурсивного поиска нескольких файлов и поиска номера строки в каждом файле, в котором найдена строка.

grep -nr "the_string" /media/slowly/DATA/lots_of_files > output.txt 

Вывод выглядит следующим образом:

  /media/slowly/DATA/lots_of_files/lots_of_files/file_3.txt:3:the_string /media/slowly/DATA/lots_of_files/lots_of_files/file_7.txt:6:the_string is in this sentence. /media/slowly/DATA/lots_of_files/lots_of_files/file_7.txt:9:the_string is in this sentence too. 

Как показано выше, вывод включает имя файла, номер строки и весь текст в этой строке, включая строку.

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

  sed '3!d' /media/slowly/DATA/lots_of_files/lots_of_files/file_3.txt > print.txt sed '6!d' /media/slowly/DATA/lots_of_files/lots_of_files/file_7.txt >> print.txt sed '9!d' /media/slowly/DATA/lots_of_files/lots_of_files/file_7.txt >> print.txt 

Я создал эти команды вручную, читая номера строк и имена файлов

Вот мой вопрос.

Q1a

Есть ли способ объединить оба шага в одну команду? Я подумываю о том, чтобы указать номер строки и имя файла в sed и распечатать строку. У меня возникла проблема с порядком, в котором генерируется выход grep.

Q1b

То же, что и выше, но также печатать две строки до и 2 строки после строки, содержащей строку (всего 5 строк)? Я подумываю о том, чтобы указать номер строки и имя файла в sed и распечатать все необходимые строки.

Большое спасибо.

Если я правильно понимаю вопрос, вы можете выполнить это с помощью одной команды grep.

Для Q1a ваш выход grep может подавлять имя файла с помощью -h , например:

 grep -hnr "the_string" /media/slowly/DATA/lots_of_files > output.txt 

Для Q1b ваш вывод grep может включать в себя строки, предшествующие и следующие согласованные строки с использованием -A и -B , например:

 grep -hnr -A2 -B2 "the_string" /media/slowly/DATA/lots_of_files > output.txt 

Выход будет содержать разделитель между совпадениями, который можно подавить с помощью --no-group-separator , например:

 grep -hnr -A2 -B2 --no-group-separator "the_string" /media/slowly/DATA/lots_of_files > output.txt 

Обратите внимание, что на выходе используется другой разделитель для сопоставления строк ( : и контекстных строк ( - ).

На ваш первый вопрос, насколько мне известно, можно ответить, придя к grep по-другому. Когда вы отправляете ему список файлов (или каталог для повторной обработки с помощью -r или -R ), он всегда выводит файл, в котором он нашел совпадение, а также номер строки. Вы можете обойти это с помощью такой конструкции, как:

 find /path/to/files -type f | xargs grep -n 'the_pattern' 

Что касается второго вопроса, если вы хотите видеть строки до и после матча, вы можете использовать переключатель -C (для C ontext):

 grep -C2 'pattern' /path/to/file # displays the two lines before and after a match 

Связанные с -C-A (для A fter) и -B (для B efore), которые дают только указанное количество строк после или до матча соответственно.

Вы можете совместить два ответа:

 find /path/to/files -type f | xargs grep -n -C2 'the_pattern' 

Что касается вашего вопроса о sed , то пример, который вы дали, работает только в том случае, если вы уже знаете номера строк. Вы также можете сделать что-то вроде:

 sed -n '/the_pattern/p' /path/to/files/* 

(но он не будет возвращаться в подкаталоги)

 find /media/slowly/DATA/lots_of_files -type f -exec grep -h -C2 'the_pattern' {} + 

Это найдет вещи, которые являются файлами (в отличие от каталогов или ссылок) в каталоге / media / slow / DATA / lots_of_files. Он будет группировать их (без необходимости в xargs в этом десятилетии) и запускать grep на них. grep не будет печатать имена файлов (-h), но даст две строки контекста до и после соответствующих строк (-C2, используйте -A и -B для более точного управления).

Преимущество этой команды над командой @cherdt заключается в том, что вы можете добавить дополнительные фильтры в команду find, например, вы можете не входить в такие каталоги, как .git