Как извлечь в Linux некоторые группы захвата с помощью командной строки в стиле php / preg?

Использовать - , чтобы указать конец параметров для ls :

ls -- -*

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

ls ./-*

Если вы хотите введите дополнительные параметры для ls , поместите их перед - или ./ например

ls -l -- -*
ls -l ./-*
2
23.03.2016, 13:58
3 ответа
pcregrep -io1 'something="(\w+)"' myfile.txt

(-i для поиска без учета регистра, -o1 для печати первой группы захвата).

GNU grep поддерживает -P (если он построен с поддержкой регекса, совместимого с perl) и -o. Однако его -o ограничен печатью всей совпадающей части. Однако вы можете использовать операторы perl для обхода этого:

grep -iPo '(?<=something=")\w+(?=")' myfile.txt

(то есть, regexp, который соответствует последовательности символов компонентов слова при условии, что за ним следует something="" и за ним следует ").

Или с достаточно свежим PCRE:

grep -iPo 'something="\K\w+(?=")' myfile.txt

(где \K сбрасывает начало совпадающей строки).

Но если вы собираетесь использовать регекспы perl, вы можете использовать perl:

perl -C -lne 'print for /something="(\w+)"/ig' myfile.txt

С GNU или BSD sed, чтобы вернуть только самое правое совпадение в строке:

sed -nE 's/.*something="(\w+)".*/\1/pi' myfile.txt

Портативно (поскольку расширенная поддержка regex и нечувствительное к регистру соответствие являются нестандартными расширениями, поддерживаемыми не всеми реализациями sed):

sed -n 's/.*[sS][oO][mM][eE][tT][hH][iI][nN][gG]="\([[:alnum:]_]\{1,\}\)".*/\1/p' myfile.txt

Это предполагает, что прописная i - это I. Это означает, что в локалях, где прописные i это, например, İ, поведение будет отличаться от предыдущего решения.

Стандартное/портативное решение, которое может найти все вхождения в строке:

awk '{while(match(tolower($0), /something="[[:alnum:]_]+"/)) {
    print substr($0, RSTART+11, RLENGTH-12)
    $0 = substr($0, RSTART+RLENGTH-1)}}' myfile.txt

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

Загвоздки:

  • Между всеми этими решениями будут некоторые различия в том, что \w[[:alnum:]_]) соответствует в локалях, отличных от C/POSIX. В любом случае он должен, по крайней мере, включать подчеркивание, все десятичные арабские цифры и буквы латинского английского алфавита (прописные и строчные). Если вам нужны только эти буквы, установите локаль на C.
  • Как уже упоминалось, нечувствительное к регистру сопоставление очень сильно зависит от локали. Если вам важны только a-z против A-Z английских букв, вы можете снова установить локаль на C.
  • The . оператор regexp в GNU-реализации sed, по крайней мере, никогда не будет соответствовать последовательностям байтов, которые не являются частью допустимого символа. В локали UTF-8, например, это означает, что он не будет сопоставлять символы однобайтовой кодовой системы с установленным 8-м битом. Другими словами, чтобы решение sed работало правильно, набор символов, используемый во входном файле, должен быть таким же, как и в локали пользователя.
  • perl, pcregrep и утилиты GNU обычно работают со строками любой длины, содержащими любое произвольное значение байтов (но обратите внимание на оговорку выше), и рассматривают дополнительные данные после последнего символа новой строки как дополнительную строку. Другие реализации этих утилит могут этого не делать.
  • Приведенные выше шаблоны поочередно сопоставляются с каждой строкой во входных данных. Это означает, что они не могут соответствовать более чем одной строке ввода. Это не проблема для шаблона типа something="\w+", который не может занимать более одной строки, но в общем случае, если вы хотите, чтобы ваш шаблон соответствовал тексту, который может занимать несколько строк, как something=".*?", то вам нужно либо:

    • изменить тип записи, с которой вы работаете. grep --null, sed -z (только GNU sed), perl -0, awk -v RS='\0' (только GNU awk и последние версии mawk) могут работать с записями, разделенными NUL, вместо строк (записи, разделенные новой строкой), GNU awk может использовать любой regexp в качестве разделителя записей (с -v RS='regexp'), perlлюбое байтовое значение (с -0ooo`).
    • pcregrep имеет для этого многострочный режим -M.
    • используйте режим slurp от perl, где весь вход - это одна запись (с -0777)

    Затем, для perl и pcre, остерегайтесь, что . не будут соответствовать символам новой строки, если не включен флаг s, например, с pcregrep -Mio1 '(?s)something="(.*?)"' или perl -C -l -0777 -ne 'print for /something="(.*? )"/gis'

  • Имейте в виду, что некоторые версии grep и pcregrep имели ошибки с -z или -M, а движки regexp вообще могут иметь некоторые встроенные ограничения на количество усилий, которые они могут приложить для соответствия regexp.
5
27.01.2020, 21:52

В linux у вас есть несколько команд, и каждая из них имеет свои особенности. - Ваша задача - найти правильный инструмент для данной работы. ;)

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

Возможно, самый простой способ - использовать perl напрямую:

cat file.txt | perl -wne '/([\w]+)/i and print $1'

Также прочитайте man grep для некоторых опций grep:

   -o, --only-matching
          Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.

Вы можете использовать, например:

cat file.txt | grep -o '\w*'

Но что лучше, действительно зависит от вашей проблемы. Если вам нравится php, вы можете использовать php даже из командной строки.

3
27.01.2020, 21:52

Это еще один ответ, основанный на perl, в нем используется perl -ne, который передает/использует все строки ввода в программу perl.

В программе perlесть оператор if, содержащий ваше регулярное выражение с группой захвата, и, когда мы находим совпадение, мы печатаем его.

Когда мы печатаем группу захвата, мы добавляем новую строку. Новая строка необходима для того, чтобы несколько совпадений были разделены новой строкой, иначе все ваши результаты будут смешаны вместе в одной строке и могут привести к неожиданному/нежелательному результату.

Если мы получим несколько строк, соответствующих группе захвата, в большинстве случаев нас интересует только первая совпадающая строка, следовательно, использование head -1.

Следующий сценарий bashиллюстрирует, как мы можем использовать его для обработки входного файла и сохранения извлеченного результата в переменной value.

cat file.txt # something="nice"
value=$(cat file.txt | perl -ne 'if (/something="([\w]+)"/) { print $1. "\n" }' | head -1)
echo $value # nice
0
31.08.2021, 00:37

Теги

Похожие вопросы