Как безопасно использовать вывод grep в скрипте?

Как безопасно использовать вывод grep в скрипте?

В скрипте я хочу найти файлы, содержащие текст. Мне нужно знать файл, в котором находится текст, и полную строку в файле, в котором находится текст. 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, справится с вашим вопросом.


Возможно, имеет смысл изменить соглашение об именовании файлов.

Связанный контент