Вопрос или проблема
Как я могу использовать 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, пожалуйста, не стесняйтесь обращаться за помощью.