Спустя два года после того, как на этот вопрос был дан ответ, теперь проще, чем когда-либо прежде, запускать программы, созданные в Guix, на другом дистрибутиве Linux. Вместо того, чтобы устанавливать Guix в другой дистрибутив Linux, мы используем guix pack
для преобразования пакета Guix либо в отдельный -tar-архив, либо в образ докера. Они даже знают о сравнении со Snap/Flatpack, о котором вы найдете некоторые комментарии в разделе «Tarballs vs. Snap, Flatpak, Docker и т. д.». Объясняется здесь:https://guix.gnu.org/blog/2018/tarballs-the-ultimate-container-image-format/
Я бы предложил отделить проверку достоверности чисел и вычисление суммы цифр от итерации по аргументам строки команды -. Это может упростить чтение.
Следующий пример сообщает обо всех обнаруженных ошибках (, а не только о первой ), «потому что мы можем».
Он не поддерживает отрицательные числа, но Bash поддерживает, поэтому тривиальная модификация glob (, такая как @(0|-)
вместо 0
), может при необходимости добавить эту поддержку. (Тогда я не уверен, какой должна быть сумма цифр; может положительный, может отрицательный.)
#!/bin/bash
shopt -s extglob
set -uo pipefail
sum_digits_in_number() {
if [[ "$1" != @(0|[1-9]*([0-9])) ]]; then
echo -n " [['${1}' is not a number]]" 1>&2
return 1
fi
local -i n="$1" sum=0
while ((n)); do
((sum += n % 10)) || :
((n /= 10)) || :
done
echo -n " $((sum))"
}
sum_digits() {
local arg
local -i errors=0
for arg in "$@"; do
sum_digits_in_number "$arg" || ((++errors))
done
if ((errors)); then
echo -e "\\n$((errors)) error(s)." 1>&2
return 1
fi
echo
}
Проверим!
# Valid calls:
sum_digits 19 115 21
sum_digits 0
sum_digits 1 0
sum_digits {100..0}
sum_digits {1..100}
# Wrong calls:
sum_digits 00 # 1 error
sum_digits {0..10} z # 1 error
sum_digits z {0..10} # 1 error
sum_digits 1z 3 z1 # 2 errors
sum_digits a b c d # 4 errors
Кроме того, вы также можете суммировать цифры, разрезая целое число $n
так, как если бы оно было строкой, например:
sum_digits_in_number() {
if [[ "$1" != @(0|[1-9]*([0-9])) ]]; then
echo -n " [['${1}' is not a number]]" 1>&2
return 1
fi
local -i n="$1" sum=0 i
for ((i = 0; i < ${#n}; ++i)); do
((sum += ${n:i:1}))
done
echo -n " $((sum))"
}
И последнее, но не менее важное: суффикс || :
нужен только для того, чтобы скрипт работал (при желании)(также )в режиме set -e
. В противном случае, если последняя цифра равна нулю, то ((sum += n % 10))
«сбой». Вместо этого можно было бы выполнить sum+='n % 10'
, что прекрасно работало бы (, используя целочисленное вычисление, как и ожидалось ), и никогда не подводило. Кроме того, обратите внимание, что вторая версия sum_digits_in_number
не имеет || :
просто потому, что она итерирует от первой цифры, а не от последней и,запретив 0
в качестве первой цифры (, чтобы избежать путаницы с восьмеричными числами, например. echo $((010))
говорит 8
), мы можем быть уверены, что +=
всегда будет «успешным».
Использование Raku (, ранее известного как Perl _6)
raku -e '.put for @*ARGS.map( *.comb).map( *.sum);' 19 115 21 22 20
Выход:
10
7
3
4
2
Выше приведено решение, закодированное на Raku, члене семейства языков Perl -. Вкратце, значения командной строки принимаются в массив @*ARGS
, каждое значение разбивается на отдельные символы(comb
-ed ), отдельные символы — sum
med.
Обратите внимание: если вам интересно поиграть с числами, Raku предоставляет несколько очень умныхRat
-функциональных функций для числовых чисел, таких как функцияnude
("Числитель DEnominator" )ниже.
raku -e ' say(.nude, " == ",.Num ) for @*ARGS.map( *.Rat);' 1 2/2 1/2 3/3 2/3 1/3 4/4 3/4 2/4 1/4
Выход:
(1 1) == 1
(1 1) == 1
(1 2) == 0.5
(1 1) == 1
(2 3) == 0.6666666666666666
(1 3) == 0.3333333333333333
(1 1) == 1
(3 4) == 0.75
(1 2) == 0.5
(1 4) == 0.25
https://docs.raku.org/language/variables#index-entry-@*АРГС
https://docs.raku.org/type/Rational
https://raku.org/