Более простая обработка опций сценария оболочки

ip link set arp off dev eth0 ; ip link set arp on dev eth0

Обязательно сделайте все это сразу, чтобы не нарушить сетевое подключение, прежде чем вы сможете снова включить ARP.

2
16.05.2014, 00:39
2 ответа

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

ПРИМЕЧАНИЕ
Некоторые функции, например, функции вывода мультиинтерфейса ifHelpShow() и uiShow() используются, но не включены сюда, так как их вызовы содержат соответствующую информацию, но их реализации не содержат.

###############################################################################
# FUNCTIONS (bash 4.1.0)
###############################################################################

function isOption () {
  # isOption "$@"
  # Return true (0) if argument has 1 or more leading hyphens.
  # Example:
  #     isOption "$@"  && ...
  # Note:
  #   Cannot use ifHelpShow() here since cannot distinguish 'isOption --help'
  #   from 'isOption "$@"' where first argument in "$@" is '--help'
  # Revised:
  #     20140117 docsalvage
  # 
  # support both short and long options
  [[ "${1:0:1}" == "-" ]]  && return 0
  return 1
}

function optionArg () {
  ifHelpShow "$1" 'optionArg  --option "$@"
    Echo argument to option if any. Within "$@", option and argument may be separated
    by space or "=". Quoted strings are preserved. If no argument, nothing echoed.
    Return true (0) if option is in argument list, whether an option-argument supplied
    or not. Return false (1) if option not in argument list. See also option().
    Examples:
        FILE=$(optionArg --file "$1")
        if $(optionArg -f "$@"); then ...
        optionArg --file "$@"   && ...
    Revised:
        20140117 docsalvage'  && return
  #
  # --option to find (without '=argument' if any)
  local FINDOPT="$1"; shift
  local OPTION=""
  local ARG=
  local o=
  local re="^$FINDOPT="
  #
  # echo "option start: FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG, @=$@" >&2
  #
  # let "$@" split commandline, respecting quoted strings
  for o in "$@"
  do
    # echo "FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG" >&2
    # echo " o=$o"  >&2
    # echo "re=$re" >&2
    #
    # detect --option and handle --option=argument
    [[ $o =~ $re ]]  && { OPTION=$FINDOPT; ARG="${o/$FINDOPT=/}"; break; }
    #
    # $OPTION will be non-null if --option was detected in last pass through loop
    [[ ! $OPTION ]]  && [[ "$o" != $FINDOPT ]]   && {              continue; } # is a positional arg (no previous --option)
    [[ ! $OPTION ]]  && [[ "$o" == $FINDOPT ]]   && { OPTION="$o"; continue; } # is the arg to last --option
    [[   $OPTION ]]  &&   isOption "$o"          && {                 break; } # no more arguments
    [[   $OPTION ]]  && ! isOption "$o"          && { ARG="$o";       break; } # only allow 1 argument
  done
  #
  # echo "option  final: FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG, @=$@" >&2
  #
  # use '-n' to remove any blank lines
  echo -n "$ARG"
  [[ "$OPTION" == "$FINDOPT" ]]   && return 0
  return 1
}

###############################################################################
# MAIN  (bash 4.1.0) (excerpt of relevant lines)
###############################################################################

# options
[[ "$@" == ""            ]]   && { zimdialog --help           ; exit 0; }
[[ "$1" == "--help"      ]]   && { zimdialog --help           ; exit 0; }
[[ "$1" == "--version"   ]]   && { uiShow "version $VERSION\n"; exit 0; }

# options with arguments
TITLE="$(optionArg --title  "$@")"
TIP="$(  optionArg --tip    "$@")"
FILE="$( optionArg --file   "$@")"
0
29.04.2021, 00:51

Здесь есть отличный ответ, но OP явно просил более простую обработку параметров командной строки. Я думаю, что не может быть более простого способа разбора сложных параметров оболочки, чем использование getoptиз util -linux:

$ cat opts.sh 
#!/bin/bash

# Print usage and exit
usage() {
    exec >&2 # Write everything to STDERR (consistent with getopt errors)
    (($#)) && echo "$@"
    echo "Usage: $0 [opts...] [args...]"
    exit 1
}

# Use getopt to validate options and reorder them. On error print usage
OPTS=$(getopt -s bash -o 'ab:c' -l 'longopt,longopt2,longwitharg:' -- "$@") || usage

# Replace our arguments with the reordered version
eval set -- "$OPTS"

# At this point everything up to "--" is options
declare opt_a opt_c longopt longopt2 longwitharg
declare -a opt_b  # Array to accumulate -b arguments
while (($#))
do
    case $1 in
        -a) opt_a=1;;
        -b) opt_b+=("$2"); shift;;
        -c) ((++opt_c));;
        --longopt) longopt=1;;
        --longopt2) ((++longopt2));;
        --longwitharg) longwitharg=$2; shift;;
        --) shift; break;; # We're done with options, shift over "--" and move on...
        *) usage "Unknown argument: $1" # Should not happen unless getopt errors are ignored.
    esac
    # Always shift once (for options with arguments we already shifted in the case so it's the 2nd shift)
    shift
done

echo "Remaining arguments after parsing options: $#"
# Now you can work directly with "$@" or slurp it in an array
args=("$@")

# Here's what we're left with:
declare -p opt_a opt_b opt_c longopt longopt2 longwitharg

# This is how you iterate over an array which may contain spaces and other field separators
for file in "${args[@]}"
do
    echo "File arg: $file"
done

getoptвыполнит свою проверку и вернет ошибку (, если вы не скажете ей не делать этого, тогда вы можете поймать их самостоятельно ). Например:

$./opts.sh --badopt
getopt: unrecognized option '--badopt'

Все остальное упорядочено и указано правильно:

$./opts.sh -ab3 -b8 file1 -ccc --longopt --longwitharg=abc --longwitharg "abc def" "file with spaces" 
Remaining arguments after parsing options: 2
declare -- opt_a="1"
declare -a opt_b=([0]="3" [1]="8")
declare -- opt_c="3"
declare -- longopt="1"
declare -- longopt2
declare -- longwitharg="abc def"
File arg: file1
File arg: file with spaces

Аргументы здесь:

  • -a— флаг -, установленный в 1, если он присутствует
  • -bи повторяться, каждый экземпляр добавляется в массив opt_b
  • -c— счетчик, считает 3 вхождения
  • --longopt— это флаг, подобный-a
  • --longopt2— это счетчик, аналогичный -c(, который не используется в этом примере, поэтому не установлен; он по-прежнему будет рассматриваться как 0 в Арифметическом Расширении ).
  • --longwitharg— обычная опция с аргументом. В этом примере мы переопределяем его значение позже в командной строке
  • file1и file with spaces— оставшиеся аргументы, и хотя они указываются в случайных местах, они оба оказываются в конце после --после того, как getopt переупорядочивает командную строку.

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

  • Прямое присвоение переменной:longwitharg=$2
  • Корпус переключателя:case $1 in

Если вы не уверены, лишние кавычки обычно не помешают.

0
29.04.2021, 00:51

Теги

Похожие вопросы