Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание - страница 13

стр.

Хотите потребовать, чтобы ввод содержал только буквы верхнего регистра, пробелы, запятые и точки? Просто измените шаблон подстановки в строке , как показано ниже:

>sed 's/[^[: upper: ],]//g'

Эту же функцию можно использовать для простейшей проверки телефонных номеров (допускается присутствие цифр, пробелов, круглых скобок и дефисов, но не допускается наличие пробелов в начале или нескольких пробелов, идущих подряд), если использовать шаблон:

>sed 's/[^- [: digit: ]\(\)]//g'

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

>sed 's/[^[: digit: ]]//g'

Однако он будет пропускать только положительные целые числа. А что, если вам необходимо разрешить ввод отрицательных чисел? Если вы просто добавите знак «минус» в множество допустимых символов, функция признает допустимой строку -3–4, хотя совершенно очевидно, что она не является допустимым целым числом. Обработка отрицательных чисел демонстрируется в сценарии № 5.

№ 3. Нормализация форматов дат

Разработчикам сценариев часто приходится иметь дело с большим количеством разнообразных форматов представления дат, нормализация которых может быть сопряжена с разными сложностями. Самые серьезные проблемы связаны с датами, потому что они записываются самыми разными способами. Даже если потребовать ввести дату в определенном формате, например месяц-день-год, вы почти наверняка получите несовместимый ввод: номер месяца вместо названия, сокращенное название вместо полного или даже полное название со всеми буквами в верхнем регистре. По этой причине функция нормализации дат, даже самая простенькая, послужит очень хорошим строительным блоком для многих сценариев, особенно таких, как сценарий № 7.

Код

Сценарий в листинге 1.5 нормализует строки с датами, используя относительно простой набор критериев: месяц должен задаваться именем или числом в диапазоне от 1 до 12, а год — четырехзначным числом. Нормализованная строка с датой включает название месяца (в виде трехсимвольного сокращения), за которым следуют день месяца и четырехзначный год.

Листинг 1.5. Сценарий normdate

>··#!/bin/bash

>··# normdate — Нормализует поле месяца в строке с датой в трехсимвольное

>··#·· представление, с первой буквой в верхнем регистре.

>··#·· Вспомогательная функция для сценария № 7, valid-date.

>··#·· В случае успеха возвращает 0.

>··monthNumToName()

>··{

>····# Присвоить переменной 'month’ соответствующее значение.

>····case $1 in

>······1) month="Jan";; 2) month="Feb";;

>······3) month="Mar";; 4) month="Apr";;

>······5) month="May";; 6) month="Jun";;

>······7) month="Jul";; 8) month="Aug";;

>······9) month="Sep";; 10) month="Oct";;

>······11) month="Nov";; 12) month="Dec";;

>······*) echo "$0: Unknown month value $1" >&2

>········exit 1

>····esac

>····return 0

>··}

>··

>··# НАЧАЛО ОСНОВНОГО СЦЕНАРИЯ — УДАЛИТЕ ИЛИ ЗАКОММЕНТИРУЙТЕ ВСЕ, ЧТО НИЖЕ,

>··# ЧТОБЫ ЭТОТ СЦЕНАРИЙ МОЖНО БЫЛО ПОДКЛЮЧАТЬ К ДРУГИМ СЦЕНАРИЯМ.

>··# =================

>··# Проверка ввода

>··if [$# −ne 3]; then

>····echo "Usage: $0 month day year" >&2

>····echo "Formats are August 3 1962 and 8 3 1962" >&2

>····exit 1

>··fi

>··if [$3 −le 99]; then

>····echo "$0: expected 4-digit year value." >&2

>····exit 1

>··fi

>··# Месяц введен как число?

>··if [-z $(echo $1|sed 's/[[: digit: ]]//g')]; then

>····monthNumToName $1

>··else

>··# Нормализовать до 3 первых букв, первая в верхнем регистре, остальные в нижнем.

>

····month="$(echo $1|cut −c1|tr '[: lower: ]' '[: upper: ]')"

>

····month="$month$(echo $1|cut −c2-3 | tr '[: upper: ]' '[: lower: ]')"

>··fi

>··echo $month $2 $3

>··exit 0

Как это работает

Обратите внимание на третий условный оператор в этом сценарии

. Он выбрасывает из поля с месяцем все цифры и затем с помощью оператора −z проверяет, получилась ли в результате пустая строка. Если получилась, это означает, что в поле содержатся только цифры, соответственно, его можно напрямую преобразовать в название месяца вызовом функции monthNumToName, которая дополнительно проверяет номер месяца на попадание в диапазон от 1 до 12. Иначе предполагается, что первое поле во введенной строке содержит название месяца, которое нормализуется сложной последовательностью команд cut и tr с использованием двух подоболочек (то есть последовательности команд заключены в скобки $(и), которые вызывают заключенные в них команды и возвращают их вывод).