SHELLdorado Newsletter 2/2002 - June 4th, 2002 ================================================================ The "SHELLdorado Newsletter" covers UNIX shell script related topics. To subscribe to this newsletter, leave your e-mail address at the SHELLdorado home page: http://www.shelldorado.com/ View previous issues at the following location: http://www.shelldorado.com/newsletter/ "Heiner's SHELLdorado" is a place for UNIX shell script programmers providing Many shell script examples, shell scripting tips & tricks + more... ================================================================ Contents o What's new at the SHELLdorado? o Shell Tip: Shorter if..then..else o Shell Tip: Setting PATH and MANPATH variable o Shell Tip: Print each line exactly once o How to use the undocumented "alarm" function (ksh93) ----------------------------------------------------------------- >> What's new at the SHELLdorado? ----------------------------------------------------------------- o You can now search the SHELLdorado for keywords using the new search facility: http://www.shelldorado.com/search/ The starting page gives some tips on searching, but the usage is fairly intuitive. The CGI script used to process the form data and process the search results (of course a shell script) is available as an example for your own ventures into CGI scripting: http://www.shelldorado.com/search/search-swish.cgi o The "Shell Scripts" section now lists more than 200 scripts: http://www.shelldorado.com/scripts/ o The "Links" page has more than 180 pointers to shell script examples, shell scripting tutorials and references and many more shell script related resources: http://www.shelldorado.com/links/ If you have comments or suggestions for this newsletter, or even want to write an article by your own, please write me an e-mail. Heiner Steven, Editor <heiner.steven@shelldorado.com> ----------------------------------------------------------------- >> Shell Tip: Shorter if..then..else ----------------------------------------------------------------- In shell scripts many commands only should be executed if a previous command completed successfully. If we e.g. create a backup copy, we only want to remove the original file if the backup was created: if cp requests.log requests.bak then rm requests.log fi If the "then" part only consists of one statement, this can easily be shortened to cp requests.log requests.bak && rm requests.log The command following "&&" will only be executed if the previous command completed successfully, i.e. returned with a zero exit code. The "||" command can be used similar to check for an error condition: mkdir /tmp/work || exit 2 # no use in continuing This is a short and readable way to write if mkdir /tmp/work then : # success else exit 2 fi ----------------------------------------------------------------- >> Shell Tip: Setting PATH and MANPATH variable ----------------------------------------------------------------- Assignments like PATH=/usr/bin:/usr/local/bin:/usr/ucb/bin are not very easy to maintain. Using a function at this point will make life much easier. First we need a function for addpath: # construct PATH and MANPATH unset PATH # if PATH is set, unset it addpath() { if [ -d "$1" ]; then if [ X"$PATH" = "X" ]; then PATH=$1 else if echo "$PATH" | grep -v "$1" >/dev/null 2>&1 then PATH=$PATH:$1 fi fi fi } Done! Now lets add the PATH we need: PATH= addpath /bin addpath /sbin addpath /usr/bin addpath /usr/sbin addpath $HOME/bin # bin in HOMEDIR At last we have to export the variable: export PATH Thats it! Now we have a nice looking PATH. Put this in your .profile or .bashrc and you are ready to go. [This tip was contributed by Reinhold Farsch <rf@ironix.org>] ----------------------------------------------------------------- >> Shell Tip: Print each line exactly once ----------------------------------------------------------------- Sometimes we have a file with duplicate lines, and we want to print each line only once, e.g. bart lisa bart bart homer Well, "uniq" is made for this purpose, but it only detects consecutive duplicate lines. We could use "sort -u", but sometimes we don't want the sequence of the input lines changed. The following "awk" script prints each line once (the output being "bart lisa homer", each word on its own line) and does not change the sequence of the input lines: # printonce - print each line exactly once awk '!L[$0]++' "$@" And now to something completely different -- well, maybe the cryptic line of seemingly random characters deserves some explanation ;-) The idea of the AWK script is to store each input line, and print it only the first time it is seen: awk ' { # Store each line into line buffer L[], and # count how often it appeared as input: L[$0] = L[$0] + 1 if ( L[$0] == 1 ) print $0 }' This can be shortened to awk 'L[$0]++ == 0 { print $0 }' The line counter is checked for the value 0 (the line has not been seen yet), and increased by one afterwards. The very first time, the input line is printed. But the action "print $0" is the default action for AWK, hence we can omit it: awk 'L[$0]++ == 0' And if we have an boolean expression "e", e == 0 is the same as "!e", so we finally get our initial AWK one-liner: awk '!L[$0]++' ----------------------------------------------------------------- >> How to use the undocumented "alarm" function (ksh93) ----------------------------------------------------------------- If a script runs for a very long time (e.g. a backup or installation program), it's a good idea to print a progress indicator to let the impatient user know that it is still running. More generally speaking, we sometimes would like to have parts of our scripts run periodically (e.g. once a second or every minute). Although this is possible by starting a process in the background ("while sleep 1; do ...; done &"), the new KornShell (ksh93) has an easier (but undocumented) way of setting up interval timers: alarm [-r] varname interval -r: repeat alarm every "interval" seconds This build-in command sets up an interval timer that will call the "alarm" discipline function (see below) every "interval" seconds. Without the "-r" option, the function is called only once. Example: #! /usr/local/bin/ksh93 alarm -r a +1 function a.alarm { print -n "$(date +%H:%S)\r"; } read dummy # wait This example prints the current time, updated every second. The "alarm" command has to be used in the following way (the order of the commands is significant): 1. Set up the alarm timer using the "alarm" command, e.g. alarm -r progressindicator +10 2. Define an "alarm" discipline function for the variable, e.g. function progressindicator.alarm { date; } [ Thanks to Brian Hiles <bsh@rawbw.com> and Jon LaBadie <jon@jgcomp.com> for their help in solving the riddle of the mysterious "alarm" built-in command ] ---------------------------------------------------------------- If you want to comment on the newsletter, have suggestions for new topics to be covered in one of the next issues, or even want to submit an article of your own, send an e-mail to mailto:heiner.steven@shelldorado.com ================================================================ To unsubscribe send a mail with the body "unsubscribe" to newsletter@shelldorado.com ================================================================