Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 15. External Filters, Programs and Commands | Next |
Simply invoked, date prints the date and time to stdout. Where this command gets interesting is in its formatting and parsing options.
Example 15-10. Using date
1 #!/bin/bash 2 # Exercising the 'date' command 3 4 echo "The number of days since the year's beginning is `date +%j`." 5 # Needs a leading '+' to invoke formatting. 6 # %j gives day of year. 7 8 echo "The number of seconds elapsed since 01/01/1970 is `date +%s`." 9 # %s yields number of seconds since "UNIX epoch" began, 10 #+ but how is this useful? 11 12 prefix=temp 13 suffix=$(date +%s) # The "+%s" option to 'date' is GNU-specific. 14 filename=$prefix.$suffix 15 echo $filename 16 # It's great for creating "unique" temp filenames, 17 #+ even better than using $$. 18 19 # Read the 'date' man page for more formatting options. 20 21 exit 0 |
The -u option gives the UTC (Universal Coordinated Time).
bash$ date Fri Mar 29 21:07:39 MST 2002 bash$ date -u Sat Mar 30 04:07:42 UTC 2002 |
This option facilitates calculating the time between different dates.
Example 15-11. Date calculations
1 #!/bin/bash 2 # date-calc.sh 3 # Author: Nathan Coulter 4 # Used in ABS Guide with permission (thanks!). 5 6 MPHR=60 # Minutes per hour. 7 HPD=24 # Hours per day. 8 9 diff () { 10 printf '%s' $(( $(date -u -d"$TARGET" +%s) - 11 $(date -u -d"$CURRENT" +%s))) 12 # %d = day of month. 13 } 14 15 16 CURRENT=$(date -u -d '2007-09-01 17:30:24' '+%F %T.%N %Z') 17 TARGET=$(date -u -d'2007-12-25 12:30:00' '+%F %T.%N %Z') 18 # %F = full date, %T = %H:%M:%S, %N = nanoseconds, %Z = time zone. 19 20 printf '\nIn 2007, %s ' \ 21 "$(date -d"$CURRENT + 22 $(( $(diff) /$MPHR /$MPHR /$HPD / 2 )) days" '+%d %B')" 23 # %B = name of month ^ halfway 24 printf 'was halfway between %s ' "$(date -d"$CURRENT" '+%d %B')" 25 printf 'and %s\n' "$(date -d"$TARGET" '+%d %B')" 26 27 printf '\nOn %s at %s, there were\n' \ 28 $(date -u -d"$CURRENT" +%F) $(date -u -d"$CURRENT" +%T) 29 DAYS=$(( $(diff) / $MPHR / $MPHR / $HPD )) 30 CURRENT=$(date -d"$CURRENT +$DAYS days" '+%F %T.%N %Z') 31 HOURS=$(( $(diff) / $MPHR / $MPHR )) 32 CURRENT=$(date -d"$CURRENT +$HOURS hours" '+%F %T.%N %Z') 33 MINUTES=$(( $(diff) / $MPHR )) 34 CURRENT=$(date -d"$CURRENT +$MINUTES minutes" '+%F %T.%N %Z') 35 printf '%s days, %s hours, ' "$DAYS" "$HOURS" 36 printf '%s minutes, and %s seconds ' "$MINUTES" "$(diff)" 37 printf 'until Christmas Dinner!\n\n' 38 39 # Exercise: 40 # -------- 41 # Rewrite the diff () function to accept passed parameters, 42 #+ rather than using global variables. |
The date command has quite a number of output options. For example %N gives the nanosecond portion of the current time. One interesting use for this is to generate random integers.
1 date +%N | sed -e 's/000$//' -e 's/^0//' 2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 # Strip off leading and trailing zeroes, if present. 4 # Length of generated integer depends on 5 #+ how many zeroes stripped off. 6 7 # 115281032 8 # 63408725 9 # 394504284 |
There are many more options (try man date).
1 date +%j 2 # Echoes day of the year (days elapsed since January 1). 3 4 date +%k%M 5 # Echoes hour and minute in 24-hour format, as a single digit string. 6 7 8 9 # The 'TZ' parameter permits overriding the default time zone. 10 date # Mon Mar 28 21:42:16 MST 2005 11 TZ=EST date # Mon Mar 28 23:42:16 EST 2005 12 # Thanks, Frank Kannemann and Pete Sjoberg, for the tip. 13 14 15 SixDaysAgo=$(date --date='6 days ago') 16 OneMonthAgo=$(date --date='1 month ago') # Four weeks back (not a month). 17 OneYearAgo=$(date --date='1 year ago') |
See also Example 3-4.
Time zone dump: echoes the time in a specified time zone.
bash$ zdump EST EST Tue Sep 18 22:09:22 2001 EST |
Outputs very verbose timing statistics for executing a command.
time ls -l / gives something like this:
0.00user 0.01system 0:00.05elapsed 16%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (149major+27minor)pagefaults 0swaps |
See also the very similar times command in the previous section.
As of version 2.0 of Bash, time became a shell reserved word, with slightly altered behavior in a pipeline. |
Utility for updating access/modification times of a file to current system time or other specified time, but also useful for creating a new file. The command touch zzz will create a new file of zero length, named zzz, assuming that zzz did not previously exist. Time-stamping empty files in this way is useful for storing date information, for example in keeping track of modification times on a project.
The touch command is equivalent to : >> newfile or >> newfile (for ordinary files). |
Before doing a cp -u (copy/update), use touch to update the time stamp of files you don't wish overwritten. As an example, if the directory /home/bozo/tax_audit contains the files spreadsheet-051606.data, spreadsheet-051706.data, and spreadsheet-051806.data, then doing a touch spreadsheet*.data will protect these files from being overwritten by files with the same names during a cp -u /home/bozo/financial_info/spreadsheet*data /home/bozo/tax_audit. |
The at job control command executes a given set of commands at a specified time. Superficially, it resembles cron, however, at is chiefly useful for one-time execution of a command set.
at 2pm January 15 prompts for a set of commands to execute at that time. These commands should be shell-script compatible, since, for all practical purposes, the user is typing in an executable shell script a line at a time. Input terminates with a Ctl-D.
Using either the -f option or input redirection (<), at reads a command list from a file. This file is an executable shell script, though it should, of course, be non-interactive. Particularly clever is including the run-parts command in the file to execute a different set of scripts.
bash$ at 2:30 am Friday < at-jobs.list job 2 at 2000-10-27 02:30 |
The batch job control command is similar to at, but it runs a command list when the system load drops below .8. Like at, it can read commands from a file with the -f option.
Prints a neatly formatted monthly calendar to stdout. Will do current year or a large range of past and future years.
This is the shell equivalent of a wait loop. It pauses for a specified number of seconds, doing nothing. It can be useful for timing or in processes running in the background, checking for a specific event every so often (polling), as in Example 29-6.
1 sleep 3 # Pauses 3 seconds. |
The sleep command defaults to seconds, but minute, hours, or days may also be specified.
|
The watch command may be a better choice than sleep for running commands at timed intervals. |
Microsleep (the u may be read as the Greek mu, or micro- prefix). This is the same as sleep, above, but "sleeps" in microsecond intervals. It can be used for fine-grained timing, or for polling an ongoing process at very frequent intervals.
1 usleep 30 # Pauses 30 microseconds. |
This command is part of the Red Hat initscripts / rc-scripts package.
The usleep command does not provide particularly accurate timing, and is therefore unsuitable for critical timing loops. |
The hwclock command accesses or adjusts the machine's hardware clock. Some options require root privileges. The /etc/rc.d/rc.sysinit startup file uses hwclock to set the system time from the hardware clock at bootup.
The clock command is a synonym for hwclock.