Выбрать главу

$ date

Fri May 20 13:30:49 UTC 2016

Усовершенствование сценария

Имеется одно ошибочное условие, которое не проверяется сценарием: когда прошлая дата находится лишь в нескольких днях от текущей или даже в будущем. Что получится в таких ситуациях и как исправить эту ошибку? (Совет: загляните в сценарий № 101, где вы найдете дополнительные проверки, которые можно применить в этом сценарии.)

№ 101. Вычисление дней до указанной даты

Логичным дополнением сценария № 100, daysago, является другой сценарий, daysuntil. Он, по сути, выполняет те же вычисления, но сначала подсчитывает количество дней, оставшихся до конца текущего года, затем количество дней в промежуточных годах и количество дней до указанной даты в целевом году, как показано в листинге 15.5.

Код

Листинг 15.5. Сценарий daysuntil

··#!/bin/bash

··# daysuntil — фактически выполняет те же вычисления, что и daysago,

··#·· но в обратном порядке, когда текущая дата становится "датой в прошлом",

··#·· а дата в будущем — "текущей".

··# Так же, как в предыдущем сценарии, используйте 'which gdate’ в OS X

··#·· и 'which date' в Linux.

··date="$(which gdate)"

··function daysInMonth

··{

····case $1 in

······1|3|5|7|8|10|12) dim=31;; # Постоянное значение

······4|6|9|11········) dim=30;;

······2··············) dim=29;; # Зависит от года: високосный/невисокосный

······*··············) dim=-1;; # Неизвестный месяц

····esac

··}

··function isleap

··{

····# Возвращает ненулевое значение в $leapyear, если $1 — високосный год.

····leapyear=$($date −d 12/31/$1 +%j | grep 366)

··}

··#######################

··#### ОСНОВНОЙ БЛОК

··#######################

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

····echo "Usage: $(basename $0) mon day year"

····echo " with just numerical values (ex: 1 1 2020)"

····exit 1

··fi

··$date −version > /dev/null 2>&1 # Отбросить сообщение об ошибке, если появится.

··if [$? -ne 0]; then

····echo "Sorry, but $(basename $0) can't run without GNU date." >&2

····exit 1

··fi

··eval $($date "+thismon=%m;thisday=%d;thisyear=%Y;dayofyear=%j")

··endmon=$1; endday=$2; endyear=$3

··# Необходимые проверки параметров…

··daysInMonth $endmon # Инициализирует переменную $dim

··if [$endday −lt 0 −o $endday −gt $dim]; then

····echo "Invalid: Month #$endmon only has $dim days." >&2

····exit 1

··fi

··if [$endmon −eq 2 −a $endday −eq 29]; then

····isleap $endyear

····if [-z "$leapyear"]; then

······echo "Invalid: $endyear wasn't a leapyear; February had 28 days." >&2

······exit 1

····fi

··fi

··if [$endyear −lt $thisyear]; then

····echo "Invalid: $endmon/$endday/$endyear is prior to the current year." >&2

····exit 1

··fi

··if [$endyear −eq $thisyear −a $endmon −lt $thismon]; then

····echo "Invalid: $endmon/$endday/$endyear is prior to the current month." >&2

····exit 1

··fi

··if [$endyear −eq $thisyear −a $endmon −eq $thismon −a $endday −lt $thisday]

··then

····echo "Invalid: $endmon/$endday/$endyear is prior to the current date." >&2

····exit 1

··fi

··if [$endyear −eq $thisyear −a $endmon −eq $thismon −a $end −e— eq $thisday]

··then

····echo "There are zero days between $endmon/$endday/$endyear and today." >&2

····exit 0

··fi

··#### Если целевая дата находится в этом же году,

··####·· вычисления должны выполняться немного иначе.

··if [$endyear −eq $thisyear]; then

····totaldays=$(($($date −d "$endmon/$endday/$endyear" +%j) −$($date +%j)))

··else

····#### Вычислить количество дней по фрагментам,

····####·· начиная с количества дней до конца текущего года.

····#### ДНЕЙ ОСТАЛОСЬ В НАЧАЛЬНОМ ГОДУ

····# Собрать строку формата с начальной датой.

····thisdatefmt="$thismon/$thisday/$thisyear"

····calculate="$($date −d "12/31/$thisyear" +%j) −$($date −d $thisdatefmt +%j)"

····daysleftinyear=$(($calculate))

····#### ДНЕЙ В ПРОМЕЖУТОЧНЫХ ГОДАХ

····daysbetweenyears=0

····tempyear=$(($thisyear + 1))

····while [$tempyear −lt $endyear]; do

······daysbetweenyears=$(($daysbetweenyears + \

········$($date −d "12/31/$tempyear" +%j)))

······tempyear=$(($tempyear + 1))

····done

····#### ДНЕЙ В КОНЕЧНОМ ГОДУ

····dayofyear=$($date −date $endmon/$endday/$endyear +%j) # Это просто!