Я хочу использовать его 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
Это сначала отключит генерацию имени файла, потому что мы хотим использовать $process
unquoted для разделения его на отдельные слова, и если эта строка содержит шаблоны подстановки имени файла (например *
), это испортит наш анализ. Мы делаем это с помощью 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/sh
(и dash
, а также 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
, затем: пробел или конец строки.