Синтаксический анализ аргументов с отрицательными значениями с использованием getopt — есть ли способ заставить getopt игнорировать их?

#bash #getopt #command-line-arguments

#bash #getopt #аргументы командной строки

Вопрос:

Я использую getopt для анализа аргументов командной строки для скрипта. Все необязательные аргументы (-o и —long ) обрабатываются getopt, но есть также обязательные аргументы. Аргумент номер 4 может быть путем или последовательностью значений, которые могут быть отрицательными.

script.sh mandatory/path/one mandatory/path/two mandatory/file.txt -200.12,32.7,-18.7

Если аргумент 4 начинается с отрицательного значения, - вызовет getopt. Очевидно, что это нарушает работу скрипта, поскольку getopt будет жаловаться на неопределенные параметры.

Есть два обходных пути, о которых я могу подумать, но оба довольно хитрые:

  1. выполните sed в $@, чтобы заменить - на некоторую фиктивную строку, а затем sed после завершения синтаксического анализа getopt, чтобы - снова заменить фиктивную строку.
 ARGS=$(echo "$@" | sed -E "s/-([0-9])/%dummy%1/g")
set -- "$ARGS"
ARGS=`getopt -o n -l no-act -n $0 -- "$@"`
eval set -- "$ARGS"
while :; do
  case "$1" in
    -n|--no-act)
      norun=1 ;;
    --) 
      shift; break ;;
    *)
      break 
  esac
  shift
done
ARGS=$(echo "$@" | sed -E "s/%dummy%([0-9])/-1/g")
eval set -- "$ARGS"
  
  1. определите параметры с аргументами в getopt -1234567890. Это разделит обязательный аргумент 4 на -2 и 00.12,32.7,-18.7 , который можно объединить в промежуточную переменную. В конце концов, обязательные аргументы 1-3 и 4 должны быть set снова.
 ARGS=`getopt -o n1:2:3:4:5:6:7:8:9:0: -l no-act -n $0 -- "$@"`
eval set -- "$ARGS"
while :; do
  case "$1" in
    -n|--no-act)
      norun=1 ;;
    -1|-2|-3|-4|-5|-6|-7|-8|-9|-0)
      TEMPVAR=$1$2
      shift ;;
    --) 
      shift; break ;;
    *)
      break 
  esac
  shift
done
  

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

(Есть еще несколько вариантов, я упоминаю только параметр -n в примере, чтобы сократить блок кода)

РЕДАКТИРОВАТЬ: обязательный аргумент 4 должен оставаться $ 4, так как в дальнейшем будут проводиться дополнительные проверки.

Комментарии:

1. Чтобы заставить getopt прекратить чтение параметров, вы можете использовать трюк «—«: любой параметр / параметр, стоящий за ним, не принимается getopt

2. Можете ли вы привести пример кода? Я также проверил руководство, но не уверен, как его реализовать.

Ответ №1:

Существует — вроде. Проблема здесь в том, что getopt команда на самом деле не понимает ничего, кроме параметров, начинающихся с дефиса, и вы не можете убедить ее использовать что-либо, кроме дефиса, в качестве ведущего параметра. Нет способа сообщить getopt, чтобы он не обрабатывал параметр каким-либо другим способом.

Однако getopt аргументы не обрабатываются. Он просто передает это в $OPTARG переменную без какого-либо синтаксического анализа. Итак, у вас есть три варианта:

  1. Если ваши параметры являются позиционными, здесь нет причин использовать getopt . Просто используйте $1 , $2 и $3 , как обычно, и завершите работу скрипта из-за неправильного количества и / или неправильно отформатированного списка чисел. Вы всегда можете подсчитать количество аргументов и обработать последний как свой список, если хотите.
  2. С другой стороны, если ваши параметры не являются позиционными, тогда вам действительно следует подумать о том, чтобы предоставить числовому списку свой собственный параметр, а затем интерпретировать $OPTARG его особым образом.
  3. Создайте свой собственный цикл синтаксического анализа параметров, если то, что вы делаете, очень особенное. getopt предназначен для относительно простых задач, и есть такая вещь, как расширение его полезности.

Любое из вышеперечисленных действий обычно выполняется в полезных сценариях. Я призываю вас не усложнять проблему. Сценарии должны быть относительно простыми, и Bash лучше всего использовать в качестве языка построения и отправки команд. Мы живем не в те дни, когда Bash (или, может быть, просто sh ?) Являются единственными языками, доступными по умолчанию в дистрибутиве. Если вы пытаетесь выполнить довольно сложную обработку аргументов, вам следует тщательно рассмотреть, является ли язык программирования общего назначения, такой как Perl, Python или Ruby, лучшим выбором для того, что вы собираетесь делать.

Комментарии:

1. Спасибо за ваши идеи. Обязательные аргументы являются позиционными (аргумент 1-4). Однако есть 8 необязательных аргументов. Они обрабатываются getopt, а затем $# равны 4. Я согласен, что здесь лучшим выбором мог быть другой язык, и в какой-то момент может произойти перезапись в Python. Когда этот скрипт впервые появился, bash, к сожалению, был единственным вариантом по нескольким причинам.

2. Достаточно справедливо. Я был там раньше сам, поэтому я на самом деле не оценивал ваш выбор языка — просто сделал общее заявление там. в вашем случае вам, вероятно, нужен вариант № 1 — просто назначьте $1 $4 переменным, а затем переместите их, прежде чем анализировать остальные с помощью getopt. Вам действительно не следует пытаться анализировать отрицательные числа через getopt, если вы можете помочь.

3. Вероятно, вы правы. Это будет означать, что все необязательные аргументы должны быть размещены после обязательных аргументов. Было бы неплохо сохранить свободу размещения опций где угодно, но это не конец света, если это больше невозможно. Основная проблема заключается в том, что синтаксис немного меняется, и пользователи путаются.

4. Я просто понимаю, что это может еще больше усложнить ситуацию… Существует определенный необязательный аргумент, который изменяет поведение скрипта. В этом случае требуется / допускается только один обязательный аргумент.

5. В этом случае вам может быть лучше иметь два отдельных цикла синтаксического анализа параметров, в зависимости от этого необязательного аргумента. Не бойтесь немного повторяться в Bash. Почти всегда лучше быть как можно более простым при написании сценариев оболочки.