Intereting Posts
Почему ядро ​​Linux выгружает <unset> .core? Список доступных параметров команды? My Ubuntu 16.04 Установка с WordPress продолжает открывать процессы apache2, поедая память Предотвращение блокировки экрана ChromeOS при работе с другим типом Пакеты, перешедшие через мост Linux, имеют очень высокую вероятность задержки пакетов и задержки? Странное поведение «ls -a | grep ^ \. " Как использовать замещение процесса внутри case-case без получения синтаксических ошибок? Как запустить XTerm с подсказкой внизу? Загрузка Debian: прерывание цикла упорядочения (systemd) Как я могу предупредить ssh-agent при использовании определенного ключа? OpenGL в Fedora в качестве гостевой системы VMWare под Windows 7 Метод установки вручную для Fedora Как использовать sed для извлечения из xml после сопоставления с шаблоном в одном из тегов внутри? Компиляция ntfs-3g из источника не дает ntfs-3g двоичного кода Преимущества использования именованных каналов и сокетов, а не временных файлов

Передача именованных аргументов в виде массива в сценарии оболочки

У меня есть этот код в инструменте, который я сейчас создаю:

while [ $# -gt 0 ]; do case "$1" in --var1=*) var1="${1#*=}" ;; --var2=*) var1="${1#*=}" ;; --var3=*) var1="${1#*=}" ;; *) printf "***************************\n * Error: Invalid argument.*\n ***************************\n" esac shift done 

У меня есть много вариантов добавления, но пять из моих параметров должны быть сохранены как массивы. Поэтому, если я вызову инструмент, скажем, из оболочки, используя что-то вроде этого:
./tool --var1="2" --var1="3" --var1="4" --var1="5" --var2="6" --var3="7"

Как сохранить значение var1 как массив? Это возможно? И если да, то каков наилучший способ справиться с этими массивами с точки зрения эффективности, если у меня их слишком много ?.

Если в Linux (с утилитами util-linux включая getopt , или один из busybox ), вы можете сделать:

 declare -A opt_spec var1=() var2=() var4=false unset var3 opt_spec=( [opt1:]='var1()' # opt with argument, array variable [opt2:]='var2()' # ditto [opt3:]='var3' # opt with argument, scalar variable [opt4]='var4' # boolean opt without argument ) parsed_opts=$( IFS=, getopt -o + -l "${!opt_spec[*]}" -- "$@" ) || exit eval "set -- $parsed_opts" while [ "$#" -gt 0 ]; do o=$1; shift case $o in (--) break;; (--*) o=${o#--} if ((${opt_spec[$o]+1})); then # opt without argument eval "${opt_spec[$o]}=true" else o=$o: case "${opt_spec[$o]}" in (*'()') eval "${opt_spec[$o]%??}+=(\"\$1\")";; (*) eval "${opt_spec[$o]}=\$1" esac shift fi esac done echo "var1: ${var1[@]}" 

Таким образом, вы можете назвать свой сценарий следующим:

 my-script --opt1=foo --opt2 bar --opt4 -- whatever 

И getopt будет выполнять тяжелую работу по разбору, обработке и сокращению для вас.

В качестве альтернативы вы можете полагаться на тип переменной вместо указания ее в $opt_spec ассоциативного массива $opt_spec :

 declare -A opt_spec var1=() var2=() var4=false unset var3 opt_spec=( [opt1:]=var1 # opt with argument [opt2:]=var2 # ditto [opt3:]=var3 # ditto [opt4]=var4 # boolean opt without argument ) parsed_opts=$( IFS=, getopt -o + -l "${!opt_spec[*]}" -- "$@" ) || exit eval "set -- $parsed_opts" while [ "$#" -gt 0 ]; do o=$1; shift case $o in (--) break;; (--*) o=${o#--} if ((${opt_spec[$o]+1})); then # opt without argument eval "${opt_spec[$o]}=true" else o=$o: case $(declare -p "${opt_spec[$o]}" 2> /dev/null) in ("declare -a"*) eval "${opt_spec[$o]}+=(\"\$1\")";; (*) eval "${opt_spec[$o]}=\$1" esac shift fi esac done echo "var1: ${var1[@]}" 

Вы можете добавить короткие варианты, например:

 declare -A long_opt_spec short_opt_spec var1=() var2=() var4=false unset var3 long_opt_spec=( [opt1:]=var1 # opt with argument [opt2:]=var2 # ditto [opt3:]=var3 # ditto [opt4]=var4 # boolean opt without argument ) short_opt_spec=( [a:]=var1 [b:]=var2 [c]=var3 [d]=var4 ) parsed_opts=$( IFS=; short_opts="${!short_opt_spec[*]}" IFS=, getopt -o "+$short_opts" -l "${!long_opt_spec[*]}" -- "$@" ) || exit eval "set -- $parsed_opts" while [ "$#" -gt 0 ]; do o=$1; shift case $o in (--) break;; (--*) o=${o#--} if ((${long_opt_spec[$o]+1})); then # opt without argument eval "${long_opt_spec[$o]}=true" else o=$o: case $(declare -p "${long_opt_spec[$o]}" 2> /dev/null) in ("declare -a"*) eval "${long_opt_spec[$o]}+=(\"\$1\")";; (*) eval "${long_opt_spec[$o]}=\$1" esac shift fi;; (-*) o=${o#-} if ((${short_opt_spec[$o]+1})); then # opt without argument eval "${short_opt_spec[$o]}=true" else o=$o: case $(declare -p "${short_opt_spec[$o]}" 2> /dev/null) in ("declare -a"*) eval "${short_opt_spec[$o]}+=(\"\$1\")";; (*) eval "${short_opt_spec[$o]}=\$1" esac shift fi esac done echo "var1: ${var1[@]}" 

Я бы предложил вам взглянуть на мой General Shell Script GitHub: utility_functions.sh . Там вы увидите функцию getArgs . Он предназначен для сопоставления опций и значений.

Я вставляю здесь только функцию, но это зависит от еще нескольких функций внутри этого скрипта

 ########################## # # Function name: getArgs # # Description: # This function provides the getopts functionality # while allowing the use of long operations and list of parameters. # in the case of a list of arguments for only one option, this list # will be returned as a single-space-separated list in one single string. # # Pre-reqs: # None # # Output: # GA_OPTION variable will hold the current option # GA_VALUE variable will hold the value (or list of values) associated # with the current option # # Usage: # You have to source the function in order to be able to access the GA_OPTIONS # and GA_VALUES variables # . getArgs $* # #################### function getArgs { # Variables to return the values out of the function typeset -a GA_OPTIONS typeset -a GA_VALUES # Checking for number of arguments if [[ -z $1 ]] then msgPrint -warning "No arguments found" msgPrint -info "Please call this function as follows: . getArgs \$*" exit 0 fi # Grab the dash dash=$(echo $1 | grep "-") # Looking for short (-) or long (--) options isOption=$(expr index "$dash" "-") # Initialize the counter counter=0 # Loop while there are arguments left while [[ $# -gt 0 ]] do if [[ $dash && $isOption -eq 1 ]] then (( counter+=1 )) GA_OPTIONS[$counter]=$1 shift else if [[ -z ${GA_VALUES[$counter]} ]] then GA_VALUES[$counter]=$1 else GA_VALUES[$counter]="${GA_VALUES[$counter]} $1" fi shift fi dash=$(echo $1 | grep "-") isOption=$(expr index "$dash" "-") done # Make the variables available to the main algorithm export GA_OPTIONS export GA_VALUES msgPrint -debug "Please check the GA_OPTIONS and GA_VALUES arrays for options and arguments" # Exit with success return 0 } 

Как вы видите, эта функция будет экспортировать GA_OPTIONS и GA_VALUES. Только условие для этого состоит в том, что после опции значения должны быть списком, разделенным пробелом.

Вы могли бы назвать скрипт как ./tool ​​–var1 2 3 4 5 –var2 = "6" –var3 = "7"

Или просто используйте аналогичную логику, чтобы учесть ваши предпочтения.

Надеюсь это поможет.