В скрипте я хочу найти файлы, содержащие текст. Мне нужно знать файл, в котором находится текст, и полную строку в файле, в котором находится текст. grep
— это утилита, которая это делает, но как мне привести вывод в удобную форму, учитывая, что в именах файлов может быть :
? Есть ли какой-то --porcelain
режим, grep
который я могу использовать, вроде того, что git
часто есть у команд?
Пример: у меня есть папка, полная файлов с такими именами, test-num:1:date:jan-2
которые я хочу просмотреть с помощью grep. Файлы содержат FAILURE:<some reason>
или SUCCESS:<some reason>
(среди прочего). Мне нужен скрипт, который ищет определенные причины и сохраняет имя файла и причину (целая строка текста подойдет) для последующей обработки. Вывод может быть в любой структуре данных, если я могу запустить код поверх нее.
решение1
Нет такого понятия, как grep --porcelain
, обработка специальных символов в именах файлов всегда была второстепенной задачей в UNIX. Вы можете попробовать что-то вроде этого, ценой эффективности:
pattern='some pattern'
for file in ./*; do
grep -- "$pattern" "$file" | while read -r line; do
printf 'file: %s, line: %s\n' "$file" "$line"
done
done
решение2
В последних (-ish) версиях GNU grep есть опция -Z
, которая делает вывод однозначным, но она в основном нацелена на такие применения, как grep -lZ … | xargs -0
. Она по-прежнему работает, если вы перечисляете содержимое строк, нулевой байт заменяет двоеточие, а содержимое строки по-прежнему заканчивается новой строкой¹, но оболочки не очень хорошо справляются с нулевыми байтами, поэтому вам будет сложно разобрать этот вывод.
Одним из простых решений (с небольшим снижением производительности) является запуск grep для каждого файла по отдельности.
Другое решение — использовать язык вроде Perl или Python. Perl довольно хорошо эмулирует grep; grep REGEX
по сути, это perl -ne '/REGEXP/ and print'
.
Но вам это может и не понадобиться, если вывод на самом деле не двусмысленный. Например, если совпадающие строки не содержат двоеточий, то имя файла — это все, что находится на строке до последнего двоеточия. Если все совпадающие строки начинаются с SUCCESS
или FAILURE
и эти слова не появляются в именах файлов, то вы можете использовать это, чтобы найти разделитель и т. д.
¹ За исключением случаев, когда используется -z
фильтрация записей, завершающихся нулем, а не записей, завершающихся символом новой строки, в этом случае null является как признаком конца имени файла, так и признаком конца результата; без -o
вывода он по-прежнему однозначен, при этом чередующиеся выходные записи являются именами файлов и соответствующими записями в выводе.
решение3
Как безопасно использовать вывод grepв сценарии?
... Вывод может быть в любом видеструктура данных,пока я могу запустить на нем код.
Скрипты оболочки на самом деле не имеют структур данных. Есть массивы, но это все, и не так-то просто безопасно перенаправить вывод в массив. (Имена файловможет(Содержат символы новой строки.)
Лучший способзапустить коднад вашими файлами в скрипте оболочки — это просто запустить код над файлами, а не пытаться сохранить имена файлов для последующего использования.
Для этого используйте find
:
find somedir -type f -exec grep -q somepattern {} \; -exec somecommand {} \;
Однако, если внимательно прочитать ваш вопрос, то становится ясно, что вы на самом деле не хотитезапустить коднад вашими файлами, вы просто хотите выполнить некоторую текстовую обработку на определенных строках. В этом случае опция GNU Grep, -z
вероятно, то, что вам нужно. Это, а также знание Sed или Awk, справится с вашим вопросом.
Возможно, имеет смысл изменить соглашение об именовании файлов.