Из двух функций оболочки, представленных ниже, фактические вычисления выполняются здесь:
while set "${1#0?}" "${1#?}"
shift "$((!${#1}))"
[ "${1:-0}" -gt 0 ]
do case $1 in ([3-9]?|2[5-9])
set "$(($1%25))" "$((q+=$1/25))";;
(??) set "$(($1%10))" "$((d=$1/10))" ;;
(?) set "" "$((p=$1-(5*(n=$1>=5))))";;
esac; done
Это весь код выбора монет - он оптимизирован для возврата как можно меньшего количества монет. И мне не нужно было ничего делать, чтобы это было так, потому что так работает управляющий оператор оболочки case
- путем выбора только самого раннего возможного совпадения. Итак, все, что необходимо, - это расположить монеты в порядке от наибольшего к наименьшему, и вы никогда не превысите 3 итераций.
Единственная сложная часть вышеизложенного - это защита переносимой математической оболочки от неправильной интерпретации результатов как восьмеричных в случае 08 и 09. Это достигается удалением любых ведущих нулей при каждом запуске цикла.
Фактически, учитывая, что ваша заявленная цель состоит в том, чтобы получать ввод от интерактивного пользователя и предоставлять вывод для него, большинство функций ниже сосредоточены в основном на проверке ввода и сообщении об ошибках. Это тоже очень важный момент, особенно в том, что касается математики оболочки. Поскольку математика оболочки - это, по сути, операция eval
, состоящая из двух частей, поэтому, когда вы помещаете вводимые пользователем данные в арифметический оператор, вы, вероятно, сначала должны убедиться, что знаете, что у вас есть.
case
, опять же, моя форма goto для таких вещей.
_err()( unset parm msg IFS \
"${1##*[!_[:alnum:]]*}" || exit
parm=$1 IFS=$2 msg=$3; shift 3
eval ': "${'"$parm?\"'\$*' can't be right. \$msg"'"}"'
)
_chg() if set -- "${1#"${1%%[!0]*}"}.${2%"${2#??}"}${3+.}" "$@" &&
case $1 in
(*.*.*) shift
_err too_many_dots . "
We're fresh out of microcoins." "$@" ;;
(-*) shift
_err nice_try_pal . "
Change isn't magic money, you know." "$@" ;;
(*[!0-9.]*) shift
_err i_hate_poetry . "
We only spend numbers around here." "$@" ;;
(.00|.0|.) shift
_err that_was_easy . "
Next time try spending something." 0 00 ;;
esac || return
then set "${1##*.}" "$((q=(${1%%.*}0*4)/10+(d=(n=(p=0)))))"
while set "${1#0?}" "${1#?}"
shift "$((!${#1}))"
[ "${1:-0}" -gt 0 ]
do case $1 in ([3-9]?|2[5-9])
set "$(($1%25))" "$((q+=$1/25))";;
(??) set "$(($1%10))" "$((d=$1/10))" ;;
(?) set "" "$((p=$1-(5*(n=$1>=5))))";;
esac; done
set quarter q dime d nickel n penny p
echo Your change is:
while [ "$#" -gt 1 ]
do printf "\t$1 coins:\t$(($2))\n"
shift 2
done; fi
На самом деле он не читает
какой-либо ввод, а принимает только ввод в качестве аргументов командной строки. Вы можете получить ввод пользователя с помощью чего-то вроде:
printf '\n$ '; IFS=. read -r dollars cents dot
И напрямую передать это, например ...
_chg "$dollars" "$cents" ${dot:+""}
... а все остальное должно быть автоматическим.
Функция _err ()
- это функция многократного использования, которую я написал, которую вы можете использовать здесь или где-либо еще для сообщения об ошибках с правильным возвратом. Когда вы раскрываете unset
$ {var? Extension form}
, оболочка выводит раскрывающую форму на стандартный поток и внезапно завершает работу с ошибкой. Это не то поведение, которое обычно хорошо работает для тестов, которые вы можете выполнять самостоятельно, но если вы знаете, что какое-то условие, которое должно быть выполнено, чтобы этот параметр unset
вообще развернулся определенно является условием, которое означает, что ваш процесс должен умереть, тогда это может быть очень удобным способом. Это связано с тем, что оболочка форматирует весь вывод своим собственным стандартным способом (к которому ваш интерактивный пользователь оболочки, вероятно, уже привык) , и сразу обрабатывает ваш код выхода.
Например:
bash -c '. ~/coins.sh
_err parameter_name \
-splitter \
"Some custom message that is also thrown in." \
and my entire input arg array
'
... при запуске из командной строки возвращает 1 и печатает в stderr ...
/home/mikeserv/coins.sh: line 5: parameter_name: 'and-my-entire-input-arg-array' can't be right. Some custom message that is also thrown in.
Итак, вся верхняя половина _chg ()
посвящена для проверки правильности ввода или возврата состояния ошибки и вывода ошибки, если это не так.
Последняя четверть того же дня посвящена форматированию стандартного вывода, когда все идет хорошо, например:
sh -c '. ~/coins.sh; _chg 10 97'
Your change is:
quarter coins: 43
dime coins: 2
nickel coins: 0
penny coins: 2
Вероятно, вы ищете:
RC=$(docker wait dat_abcdetl_1)
Конструкция $(...)
используется для подстановки процесса , тогда как ${...}
предназначена для подстановки параметра .
${...}
— это конструкция, используемая для расширения параметров оболочки
When braces are used, the matching ending brace is the first ‘}’ not escaped by a backslash or within a quoted string, and not within an embedded arithmetic expansion, command substitution, or parameter expansion.
Судя по вашему примеру, вам действительно нужно Подстановка команд
Command substitution allows the output of a command to replace the command itself.
Это будет записано как:
RC=$(docker wait dat_abcdetl_1)