#regex #bash #grep #parameter-passing
#регулярное выражение #bash #grep #передача параметров
Вопрос:
Хотя заголовок вопроса конкретно касается регулярных выражений, я бы принял любые решения проблемы, которые я объясняю в теле вопроса
Контекст:
У меня есть скрипт, который передает все свои параметры ($@) другому скрипту после того, как он выполнил некоторые действия с одним из аргументов. Подробности выходят за рамки этого вопроса, но я буду рад обсудить их в разделе комментариев, если это необходимо.
То, что я ищу:
Что я хочу, так это иметь возможность изменять мое регулярное выражение (см. Ниже), чтобы мне не нужно было поддерживать белый список в формате: … (?= command1| command2| command3)
… [редактировать:] где command*
вообще может быть любое слово
Я хочу иметь возможность включать весь текстовый двоичный объект, переданный в аргумент (-p, —project), включая кавычки, если они присутствуют, в новую переменную.
Попытки:
Я успешно создал регулярное выражение, которое решает мою непосредственную проблему, пожалуйста, ознакомьтесь с объяснением здесь. Я думаю, что это объясняет мою проблему с помощью примеров.
Регулярное выражение, которое я построил:
(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)
Тестовые строки:
pretend-cli -p /path to data/path/to/data01 command1 --some-other=123
pretend-cli -p "/path to data/path/to/data02" command2 --some-other=123
pretend-cli -p '/path to data/path/to/data03' command3 --some-other=123
pretend-cli -p=/path to data/path/to/data04 command1 --some-other=123
pretend-cli -p="/path to data/path/to/data05" command2 --some-other=123
pretend-cli -p='/path to data/path/to/data06' command3 --some-other=123
pretend-cli --project /path to data/path/to/data07 command1 --some-other=123
pretend-cli --project "/path to data/path/to/data08" command2 --some-other=123
pretend-cli --project '/path to data/path/to/data09' command3 --some-other=123
pretend-cli --project=/path to data/path/to/data10 command1 --some-other=123
pretend-cli --project="/path to data/path/to/data11" command2 --some-other=123
pretend-cli --project='/path to data/path/to/data12' command3 --some-other=123
Но, как вы можете видеть, это требует, чтобы я вел белый список.
Дальнейшее объяснение
Как это будет выглядеть в текущей реализации моего скрипта (12 изолированных тестовых примеров):
PRETEND_PARAMETERS_01="-p /path to data/path/to/data01 command1 --some-other=123"
PRETEND_PARAMETERS_02="-p "/path to data/path/to/data02" command2 --some-other=123"
PRETEND_PARAMETERS_03="-p '/path to data/path/to/data03' command3 --some-other=123"
PRETEND_PARAMETERS_04="-p=/path to data/path/to/data04 command1 --some-other=123"
PRETEND_PARAMETERS_05="-p="/path to data/path/to/data05" command2 --some-other=123"
PRETEND_PARAMETERS_06="-p='/path to data/path/to/data06' command3 --some-other=123"
PRETEND_PARAMETERS_07="--project /path to data/path/to/data07 command1 --some-other=123"
PRETEND_PARAMETERS_08="--project "/path to data/path/to/data08" command2 --some-other=123"
PRETEND_PARAMETERS_09="--project '/path to data/path/to/data09' command3 --some-other=123"
PRETEND_PARAMETERS_10="--project=/path to data/path/to/data10 command1 --some-other=123"
PRETEND_PARAMETERS_11="--project="/path to data/path/to/data11" command2 --some-other=123"
PRETEND_PARAMETERS_12="--project='/path to data/path/to/data12' command3 --some-other=123"
То, как я выделяю «путь проекта» из этих параметров:
PRETEND_PROJECT_PATH_01=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_01})
PRETEND_PROJECT_PATH_02=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_02})
PRETEND_PROJECT_PATH_03=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_03})
PRETEND_PROJECT_PATH_04=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_04})
PRETEND_PROJECT_PATH_05=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_05})
PRETEND_PROJECT_PATH_06=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_06})
PRETEND_PROJECT_PATH_07=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_07})
PRETEND_PROJECT_PATH_08=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_08})
PRETEND_PROJECT_PATH_09=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_09})
PRETEND_PROJECT_PATH_10=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_10})
PRETEND_PROJECT_PATH_11=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_11})
PRETEND_PROJECT_PATH_12=$(grep -oP '(?:-p|--project)[= ]K(.*)(?= command1| command2| command3)' <<< ${PRETEND_PARAMETERS_12})
Чтобы увидеть, что содержат эти новые переменные:
echo ${PRETEND_PROJECT_PATH_01}
echo ${PRETEND_PROJECT_PATH_02}
echo ${PRETEND_PROJECT_PATH_03}
echo ${PRETEND_PROJECT_PATH_04}
echo ${PRETEND_PROJECT_PATH_05}
echo ${PRETEND_PROJECT_PATH_06}
echo ${PRETEND_PROJECT_PATH_07}
echo ${PRETEND_PROJECT_PATH_08}
echo ${PRETEND_PROJECT_PATH_09}
echo ${PRETEND_PROJECT_PATH_10}
echo ${PRETEND_PROJECT_PATH_11}
echo ${PRETEND_PROJECT_PATH_12}
Комментарии:
1. С помощью GNU
getopt
должно быть проще передавать параметры командной строки, включая длинные параметры.2. Могу ли я гарантировать, что в хост-системе будет установлен getopt?
3. Если ваш сервер работает под управлением Linux, то
getopt
command является частью пакета util-linux-ng, который установлен по умолчанию.
Ответ №1:
Bash
не поддерживает perl
возможности регулярных выражений, которые вы пытаетесь использовать. Если вам нужно придерживаться bash, проверьте, помогает ли следующее.
foo()
{
echo "invoked with '$#' arguments: [$*]"
}
run_cli()
{
path=
# look for the value of -p/--project option
for i in $(seq 1 $#); do
if [[ "${!i}" =~ (-p|--project)(.*) ]]; then
if [[ "${BASH_REMATCH[2]}" == '' ]]; then
i=$(( i 1 ))
path="${!i}"
else
path="${BASH_REMATCH[2]:1}"
fi
break
fi
done
echo "path: [$path]" # do what you want with the path
foo "$@" # call the other script here with the original set of arguments
}
# Usage examples
echo "- eg 1"
run_cli -p /path to data/path/to/data01 command1 --some-other=123
echo "- eg 2"
run_cli -p /path to data/path/to/data01 --some-other=123
echo "- eg 3"
run_cli -p=/path to data/path/to/data01 --some-other=123
Вывод:
- eg 1
path: [/path to data/path/to/data01]
invoked with '4' arguments: [-p /path to data/path/to/data01 command1 --some-other=123]
- eg 2
path: [/path to data/path/to/data01]
invoked with '3' arguments: [-p /path to data/path/to/data01 --some-other=123]
- eg 3
path: [/path to data/path/to/data01]
invoked with '2' arguments: [-p=/path to data/path/to/data01 --some-other=123]
Комментарии:
1. Я должен был уточнить, что command * может быть одним из любого глагола вообще. Я не имел в виду, что это будет иметь форму «команда *».
2. это гораздо больше похоже на правду. Просто обратите внимание, что в настоящее время он работает только с аргументом —parameter, а не с аргументом —parameter=
3. Теперь идеально, спасибо! Я нахожу это увлекательным решением, потому что это сочетание очень простых регулярных выражений и различных простых сценариев оболочки. Узнал о BASH_REMATCH.