Регулярное выражение для проверки аргументов команды

Регулярное выражение для проверки аргументов команды

Я хочу использовать его grepдля проверки того, содержит ли вызванная команда cmdслово nameв качестве аргумента. (Я знаю о about !*в Bash, но я не хочу его использовать).

Допустим, у меня есть команда в переменной с именем process.

Сначала я попробовал echo $process | grep 'cmd name'. Это недостаточно изящно, так как учитывает только один аргумент.

Поэтому я попытался посмотреть, смогу ли я захватить его как последний аргумент, используя regex cmd .*(?= )name. Идея состоит в том, чтобы захватить что угодно, за которым следует пробел, а затем name(после cmd). Но это не работает.

Моя цель, если это сработает, состояла в том, чтобы попытаться объяснить, является ли это аргументом в любой из позиций.

Как можно использовать регулярные выражения для этого?

решение1

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


Предположим, что вы храните и команду, и аргументы команды в одной строке (лучше использовать массив, см.Как можно выполнить команду, хранящуюся в переменной?), то вы можете сделать что-то вроде

process='cmd with "some arguments" and maybe name'

set -f
set -- $process

if [ "$1" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

shift

for arg do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

Это сначала отключит генерацию имени файла, потому что мы хотим использовать $processunquoted для разделения его на отдельные слова, и если эта строка содержит шаблоны подстановки имени файла (например *), это испортит наш анализ. Мы делаем это с помощью set -f.

Затем мы устанавливаем позиционные параметры для слов в $process. После этого, если "$1"есть cmd, мы знаем, что нам следует искать nameв оставшейся части командной строки. Если нет, мы останавливаемся на этом.

Мы shiftвыходим cmdиз списка позиционных параметров и начинаем просматривать аргументы в цикле. В каждой итерации мы просто сравниваем аргумент со строкой name. Если мы его находим, мы говорим об этом и выходим.

В конце цикла мы знаем, что nameаргумент не найден, поэтому сообщаем об этом и завершаем работу с ошибкой.

Обратите внимание, что в моем примере выше аргумент some argumentsбудет проанализирован как дваотдельныйstrings "someи arguments", что является одной из причин, по которой вы никогда не захотите хранить команду и ее аргументы в одной строке. Это также означает, что он обнаружит аргумент nameвнутри одного аргумента "some name string", что будет ложным срабатыванием.


Если командная строка хранится в массиве (например bash, ), то это можно сделать так:

process=( cmd with "some arguments" and maybe name )

if [ "${process[0]}" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

for arg in "${process[@]:1}"; do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

Расширением "${process[@]:1}"будет весь массив, но не первый элемент (имя команды).

Для /bin/shdash, а также bashи любой другой оболочки POSIX) вышеприведенный код будет менее многословным:

set -- cmd with "some arguments" and maybe name

if [ "$1" != 'cmd' ]; then
    echo 'The command is not "cmd"'
    exit 1
fi

shift

for arg do
    if [ "$arg" = 'name' ]; then
        echo 'Found "name" argument'
        exit
    fi
done

echo 'Did not find "name" argument in command line'
exit 1

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

решение2

Поскольку вы упомянули bash, еще одним вариантом является его оператор сопоставления с шаблоном =~:

if [[ $process =~ ^cmd[[:space:]].*name([[:space:]]|$) ]]
then
  _name_ was found as an argument to _cmd_
fi

Это позволяет определить, начинается ли содержимое переменной с cmd, за которым следует пробел, затем что-либо или ничего, затем name, затем: пробел или конец строки.

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