Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание - страница 15
>
>····while [${#remainder} −lt 3]; do # Добавить ведущие нули
>······remainder="0$remainder"
>····done
>
>
>··done
>··nicenum="${thousands}${result}"
>··if [! -z $2]; then
>····echo $nicenum
>··fi
>}
>DD="." # Десятичная точка для разделения целой и дробной части
>TD="," # Разделитель групп разрядов
># Начало основного сценария
># =================
>
>····case $opt in
>······d) DD="$OPTARG";;
>······t) TD="$OPTARG";;
>····esac
>··done
>··shift $(($OPTIND — 1))
>··# Проверка ввода
>··if [$# −eq 0]; then
>····echo "Usage: $(basename $0) [-d c] [-t c] number"
>····echo " −d specifies the decimal point delimiter"
>····echo " −t specifies the thousands delimiter"
>····exit 0
>··fi
>
>··exit 0
Как это работает
Основная работа в этом сценарии выполняется циклом while внутри функции nicenumber()
Запуск сценария
Чтобы опробовать этот сценарий, просто вызовите его с очень большим числом. Сценарий добавит десятичную точку и разделители групп разрядов, использовав значения либо по умолчанию, либо указанные с помощью флагов.
Результат можно внедрить в сообщение, как показано ниже:
>echo "Do you really want to pay \$$(nicenumber $price)?"
Результаты
Сценарий nicenumber может также принимать дополнительные параметры. Листинг 1.8 демонстрирует форматирование нескольких чисел с использованием сценария.
Листинг 1.8: Тестирование сценария nicenumber
>$ nicenumber 5894625
>5,894,625
>$ nicenumber 589462532.433
>589,462,532.433
>$ nicenumber −d, -t. 589462532.433
>589.462.532,433
Усовершенствование сценария
В разных странах используют разные символы в качестве десятичной точки и для разделения групп разрядов, поэтому в сценарии предусмотрена возможность передачи дополнительных флагов. Например, в Германии и Италии сценарию следует передать −d"." и −t",", во Франции −d"," и −t " ", а в Швейцарии, где четыре государственных языка, следует использовать −d"." и −t "'". Это отличный пример ситуации, когда гибкость оказывается ценнее жестко определенных значений, потому что инструмент становится полезным для более широкого круга пользователей.
С другой стороны, мы жестко установили, что во входных значениях роль десятичной точки будет играть символ".", то есть, если вы предполагаете использование другого разделителя дробной и целой части во входных значениях, измените символ в двух вызовах команды cut в строках
Ниже показано одно из решений:
>integer=$(echo $1 | cut −d$DD −f1) # Слева от точки
>decimal=$(echo $1 | cut −d$DD −f2) # Справа от точки
Это решение работоспособно, только если разделитель дробной и целой части во входном значении не отличается от разделителя, выбранного для результата, в противном случае сценарий просто не будет работать. Более сложное решение состоит в том, чтобы непосредственно перед этими двумя строками включить проверку, позволяющую убедиться, что разделитель дробной и целой части во входном значении совпадает с разделителем, указанным пользователем. Для реализации проверки можно использовать тот же трюк, что был показан в сценарии № 2: отбросить все цифры и посмотреть, что осталось, например:
>separator="$(echo $1 | sed 's/[[: digit: ]]//g')"
>if [! -z "$separator" −a "$separator"!= "$DD"]; then
>··echo "$0: Unknown decimal separator $separator encountered." >&2
>··exit 1
>fi
№ 5. Проверка ввода: целые числа
Как было показано в сценарии № 2, проверка целых чисел осуществляется очень просто, пока дело не доходит до отрицательных значений. Проблема в том, что всякое отрицательное число может содержать только один знак «минус», который обязан быть первым. Процедура проверки в листинге 1.9 оценивает правильность форматирования отрицательных чисел и, что особенно ценно, может проверить вхождение значений в установленный пользователем диапазон.