getopts игнорирует все аргументы, если безымянный аргумент предшествует именованным аргументам ("./foo un named -n named") - PullRequest
2 голосов
/ 18 ноября 2011

Я пытаюсь понять, почему getopts, похоже, игнорирует все аргументы, если «безымянный» аргумент предшествует любым именованным аргументам.

Используя пример из http://wiki.bash -hackers.org /howto / getopts_tutorial ,

#!/bin/bash

while getopts ":a" opt; do
  case $opt in
    a)
      echo "-a was triggered!" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done

И наблюдая за результатом:

$ ./opt_test
$ ./opt_test -a
-a was triggered!
$ ./opt_test -a -f
-a was triggered!
Invalid option: -f
$ ./opt_test a -a -f
$ ./opt_test a -a
$ ./opt_test a -f
$ ./opt_test lala -f
$ 

Таким образом, при добавлении безымянного аргумента (аргумента без тире) getopts игнорирует всеаргументы.

Почему это так и как я могу обойти это?Мне бы хотелось, чтобы моя программа могла улавливать такие вещи и печатать экран использования.

Ответы [ 4 ]

3 голосов
/ 18 ноября 2011

Это довольно стандартное поведение для программ - останавливать обработку опций, когда они сталкиваются с первым не опциональным аргументом.Это очень часто именно то, что вы хотите.Например, подумайте об этом:

ssh someremotehost ls -l

Если ssh попытается обработать параметры после первого аргумента без параметров, вы никогда не сможете передать параметры удаленным командам.Еще один стандарт, поддерживаемый getopt, заключается в том, что обработка опций явно останавливается при аргументе --, поэтому вы можете сделать что-то вроде этого, чтобы удалить файл с именем -f:

rm -- -f

Если вы действительно хотите обработать опцииВ любом месте командной строки вы можете написать свою собственную процедуру обработки опций.Это не так уж сложно, и вы можете реализовать поддержку длинных опций (--this-is-a-long-option).

2 голосов
/ 24 февраля 2014

Обходной путь, который я использую, заключается в передаче среза массива в getopts:

Вместо этого:

while getopts ":a" opt; do

Попробуйте это:

while getopts ":a" opt ${@:2}; do

Это передает getoptsанализирует аргументы со второго по последний и работает корректно, игнорируя первый аргумент.

1 голос
/ 18 ноября 2011

Цитирование из документации getopts :

«Любое из следующего должно указывать конец параметров: специальная опция« - », поиск аргумента, который не начинается с« - », или обнаружение ошибки.»

0 голосов
/ 02 марта 2015

Чтобы позволить опциям предшествовать безымянным (позиционным) аргументам, используйте shift afterwords для очистки,

, например, чтобы иметь опцию без значения:

while getopts "u" opt; do
case $opt in
  u) USE_USERNAMES="TRUE"
  ;;
  \?) echo "Invalid option -$OPTARG" >&2
  ;;
esac
done

# Clean-up after arguments parsing
if test "$USE_USERNAMES"; then
  shift 
fi

Или,со значением:

while getopts "s:" OPT; do
case $OPT in
  s) SUBMISSIONS="$OPTARG"
  ;;
  \?) echo "Invalid option -$OPTARG" >&2
      exit 1
  ;;
esac
done

# Clean-up arguments and assign default values AFTER arguments parsing
if test "$SUBMISSIONS"; then
  shift 2
else
  SUBMISSIONS="./logins.txt"
fi

# Move on to unnamed (positional) arguments
if ! test "$1"; then
  echo "ERROR: Required first argument missing"
  exit 1
fi

# Use arguments
echo "SUBMISSIONS: $SUBMISSIONS"
echo "FIRST ARG: $1"

Ссылка :

...