Как я могу использовать grep, чтобы искать только в первой строке файлов конкретную строку?

Вопрос или проблема

Как я могу использовать grep для поиска строки в файлах, но искать только в первой строке этих файлов?

Два альтернативных варианта:

С помощью awk

awk '{if ($0~"pattern") print $0; nextfile;}' mydir/*

или если ваша версия awk не поддерживает nextfile (спасибо Стефану Шазеласу за предложение):

awk 'FNR==1{if ($0~"pattern") print $0;}' mydir/*

это будет читать только первую строку перед переходом к следующему файлу и печатать её только в том случае, если она соответствует "pattern".

Преимущества заключаются в том, что можно точно настроить как поле, по которому искать шаблон (используя, например, $2 для поиска только во втором поле), так и вывод (например, $3 для печати третьего поля или FILENAME, или даже смешивать).

Обратите внимание, что с версией FNR (“номер текущей входной записи”, т.е. номер строки) можно более точно настроить строки, по которым вы хотите использовать grep: FNR==3 для третьей строки, FNR<10 для первых 10 строк и т.д. (Я думаю, в этом случае, если вы имеете дело с очень большими файлами и ваша версия awk поддерживает это, вы можете захотеть смешать FNR с nextfile для улучшения производительности.)

С помощью head, сохраняя имена файлов

head -n1 -v mydir/files*|grep -B1 pattern

-v опция head будет печатать имена файлов, а опция -B1 grep будет печатать предыдущую строку из соответствующих строк — то есть, имена файлов. Если вам нужны только имена файлов, вы можете передать это дальше в grep:

head -n1 -v mydir/*|grep -B1 pattern|grep ==>

Как заметил don_crissti в комментариях, будьте осторожны с именами файлов, которые соответствуют шаблону сами по себе…

Используя GNU grep:

grep -m1 ^ * |grep 'pattern'

рекурсивно:

grep -rm1 ^ . |grep 'pattern'

Я реализовал комментарий @Rob и успешно получил желаемый результат.

Замените string на вашу строку.

grep -Rin "string" . | grep ":1:.*string" > result.txt

Это выполняет рекурсивный поиск без учета регистра для string в текущем каталоге и выводит номера строк. Затем он ищет вхождения в файлах, которые находятся на первой строке, и сохраняет вывод в файл с именем result.txt.

Вот perl-однострочник для того, чтобы сделать именно это

perl -ne 'print if /MY_SEARCH_STRING/; exit' myfile.txt

Это проверит, есть ли ключевое слово MY_SEARCH_STRING в первой строке файла myfile.txt. Если вам нужно искать во всем файле, просто удалите exit из однострочника.

мы можем попробовать и с командой sed

sed -n '1p' filename| sed -n '/pattern/p'

Используя find для вызова head и grep:

find . -type f -exec head -n 1 {} \; | grep -e "$pattern"

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

Используя вместо этого sed:

find . -type f -exec sed -n '/pattern/p;q' {} \;

Это вызывает sed для каждого обычного файла. Выражение sed печатает текущую строку, если она соответствует шаблону pattern. Затем оно сразу же завершает работу.

Вот (плохой) пример perl-скрипта, который делает что-то подобное:

#!/usr/bin/perl -w

foreach (@ARGV) {
    my $filename = $_;
    open my $file, '<', $filename; 
    my $line = <$file>; 
    close $file;

    print "$filename\n" if $line =~ /your-match-text/;
}

Вам нужен список полных строк в качестве результата, или вам нужен список файлов, содержащих строку?
Это будет искать строку номер один(-n1) в оболочках (*.sh) и собирать строки, содержащие ‘bash’:

head -n1 *.sh | grep bash > fullstring.txt

fullstring.txt будет содержать что-то вроде этого:

#!/bin/bash
#!/bin/bash

(GNU) grep поддерживает Регулярные выражения, совместимые с Perl (PCRE), используя флаг -P.
PCRE поддерживает настройки опций.
Одна из этих настроек — (?m) для активации и (?-m) для деактивации многострочности

Сочетая все это, вы можете найти все файлы в текущем каталоге, соответствующие <pattern>, следующим образом:

grep -lrP '(?-m)^(?m)<pattern>' .

Примечание: Я повторно включил многострочность после совпадения с началом файла с ^, что позволяет использовать $ в конце шаблона для совпадения с целой первой строкой.


Это также работает с git grep.
Например, чтобы соответствовать всем отслеживаемым файлам в рабочем дереве, начинающимся с #!/usr/bin/env bash, и вызвать shellcheck для них:

git grep -lzP '(?-m)^(?m)#!/usr/bin/env bash$' | xargs -0 shellcheck

Попробуйте что-то подобное.
Создайте файл finder.sh с содержимым.
Измените параметры в файле в соответствии с вашими потребностями.

#!/bin/bash

# Где искать
DIR="/path/search/dir"

# Строка поиска
SEARCH="my-string"

FILES=$(find "$DIR" -type f)

for F in $FILES; do
   head -1 $F | grep -w "$SEARCH"
done

Сохраните файл и выполните chmod +x finder.sh

Запустите ./finder.sh

Примечание: если вы собираетесь искать в файлах с привилегиями суперпользователя, вам нужно использовать sudo или учетную запись пользователя root.

Попробуйте:

$ case "$(head -n 1 < file)" in (*pattern*) echo Match ;; esac
Match

Ответ или решение

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

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

Один из самых простых способов — это использовать grep в сочетании с другими командами, такими как head. Чтобы выполнить поиск строки в первой строке файлов, можно воспользоваться следующим подходом:

head -n 1 mydir/* | grep "ваша_строка"

Здесь:

  • head -n 1 mydir/* выводит первую строку из каждого файла, расположенного в директории mydir.
  • grep "ваша_строка" осуществляет поиск в строках, возвращенных предыдущей командой.

Однако, если вам нужно сохранить информацию о том, в каком файле была найдена строка, можно использовать параметр -v (verbose) в команде head:

head -n 1 -v mydir/* | grep "ваша_строка"

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

Команда awk предлагает более детализированный подход к фильтрации данных. Например, можно использовать следующую команду:

awk 'FNR==1 && /ваша_строка/ {print FILENAME, $0; nextfile}' mydir/*

В этом случае:

  • FNR==1 указывает на обработку только первой строки.
  • && /ваша_строка/ проверяет, содержится ли строка в итоговом выводе.
  • {print FILENAME, $0; nextfile} — выводит имя файла и саму строку при совпадении.

Рекурсивный поиск с grep

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

grep -rm 1 '' mydir/ | grep "ваша_строка"
  • -r указывает на рекурсивный поиск.
  • -m 1 сообщает grep остановиться после первой строки, в которой находится соответствие.

Использование find и других утилит

Для более гибкого подхода можно воспользоваться find, чтобы выбрать файлы и передать их в head и grep:

find . -type f -exec head -n 1 {} \; | grep "ваша_строка"

Здесь:

  • find . -type f находит все файлы в текущей директории.
  • -exec head -n 1 {} выполняет head для каждого найденного файла.

Также можно использовать sed так:

find . -type f -exec sed -n '1p' {} \; | grep "ваша_строка"

Здесь sed -n '1p' выводит только первую строку каждого файла.

Заключение

Каждый из предложенных методов имеет свои преимущества. Выбор подхода зависит от ваших конкретных требований и структуры файловой системы. Использование grep, awk, find, head и sed позволяет создать мощные инструменты для фильтрации данных, что особенно полезно при работе с большими объёмами информации.

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

Оцените материал
Добавить комментарий

Капча загружается...