To use HERE documents, cat > some.file << EOF blah blah blah EOF To make it look nicer inside of scripts, you can tell ksh to ignore leading tabs by using <<- instead of just <<. if [[ ! -f some.file ]] then cat > some.file <<- EOF blah blah blah EOF fi ksh does parameter and arithmetic expansions inside a HERE document. If you don't want this (perhaps you have literal $'s), quote the EOF. cat > /etc/rc.local <<- 'EOF' blah blah blah EOF ----------------------------------------------------------------------- To set variable defaults, input_file=${1:-default.file.name} ----------------------------------------------------------------------- To remove only selected mail, rmm $(scan | grep expression | awk '{print $1}' | tr -d '+') ----------------------------------------------------------------------- When wanting to pass along all your input parameters to another program, for example, when writing wrappers or front-ends, use "$@". This will do what you need for the parms, double-quoting them so that originally quoted strings, don't get broken up, e.g. "This is one parm". ----------------------------------------------------------------------- To specify binary, hex, or octal data with ksh, you need to use print's octal escape sequence, probably also with its \c option to avoid the newline at the end of what you're "printing". For example, on 4-12-2001, I came across a link in penguin's /etc directory with a 1-byte name, which was x'01'. Bizarre yes, but how do you erase that? Here's how: rm $(print '\01\c') ----------------------------------------------------------------------- To format some output, use printf like so for i in ar*;do echo "$(printf %-14s $i) has" \ "$(printf %4s $(grep -c patent\.cache\.[0-9] $i)) cache and" \ "$(printf %4s $(grep -c patent\.fpcache\.[0-9] $i)) fpcache" \ "out of $(printf %4s $(wc -l $i|awk '{print $1}')) total." done This produces output similar to ar0071e0.scsi0 has 0 cache and 0 fpcache out of 3 total ar0071e0.scsi1 has 0 cache and 0 fpcache out of 29 total ar0071e0.ssa0 has 5000 cache and 2500 fpcache out of 7500 total ar0072e0.scsi0 has 0 cache and 0 fpcache out of 10 total ar0072e0.scsi1 has 0 cache and 0 fpcache out of 1 total ar0072e0.ssa0 has 2500 cache and 5000 fpcache out of 7500 total ar0073e0.scsi0 has 0 cache and 0 fpcache out of 1 total ar0073e0.ssa0 has 2500 cache and 2500 fpcache out of 5001 total Note the minus sign in the first printf to left justify the filename, versus the right-justification of the numbers. The format specificier has the format of %-0w.pf, where |||| || Start of format specifier --/||| || Optional Left-Justify Indicator --/|| || Optional Left fill with 0's Indicator --/| || Optional Minimum Width --/ || Optional Precision (# of decimal places) --/| Datatype of value, examples are --/ s = Character string d = Integer or i = Integer x = Lowercase hex Integer (0-9a-f) X = Uppercase hex Integer (0-9A-F) f = Float ----------------------------------------------------------------------- To check a parm for any number of possible values, if [[ $parm2check = @(any|number|of|possible|values) ]] then fi Beware of extra spaces and case. ----------------------------------------------------------------------- Here's the syntax for something intended to by typed in at the prompt, for i in *; do echo $i; done or for i in 100 99 98 97 96 95 94 93 92 91 90; \ do grep $i/100 pingtest.out |grep 253| wc;done or better yet, for j in 161 181 253;do echo "------ This is $j ------";\ for i in 100 99 98 97 96 95 94 93 92 91 90; \ do grep $i/100 pingtest.out |grep $j| wc;done;done or even better, c;echo $(wc -l pingtest.out) "lines in pingtest.out"; \ head -1 pingtest.out;tail -1 pingtest.out; \ for j in 161 181 253;do echo "------ This is $j ------"; \ for i in 100 99 98 97 96 95 94 93 92 91 90; \ do grep $i/100 pingtest.out |grep $j| wc -l;done;done ----------------------------------------------------------------------- Here's a command that loops, waiting for something to happen i=0;until fs la /afs/alm/cs/datafactory/Pserver/source/makepass | \ grep jasper;do echo "Not yet after $i seconds...";((i=$i+10)); \ sleep 10;done;echo "It finally got done at" `date` If you want to get fancy and have an alarm go off when this is done, try echo "Got a hit at $(date)" while print -n '\a\a\a\a\a\a\a\a\a\a' do sleep 2 done The \a's are to sound the bell, and the -n keeps it all on the same line, thus keeping your "Got a hit" message on the screen. To one-line it, while print -n '\a\a\a\a\a\a\a\a\a\a';do sleep 2;done Or if you want to loop indefinitely, while sleep 2;do ls -l ;done ----------------------------------------------------------------------- Here's a command that loops, waiting for something to finish i=0;until [[ `ps -ef | grep 22502 | grep -v grep` = "" ]];do \ echo "Not yet after $i minutes";((i=$i+1));sleep 60;done; \ echo "It finally got done at" `date` "after $i minutes." or another example, this waits for a 24,110,013-byte log file to change, mins=2;until (( $(ls -l /var/adm/sng/logs/fwreg_l4.log|awk '{print $5}') \ != 24110013 )) ;do ((mins=$mins+1));sleep 60;done; \ echo "It finally changed at" `date` "after $i minutes." or this example, waiting for an SSA array to rebuild itself, a=1;while (( $a != 0 ));do \ a=$(/usr/ssa/ssaraid/bin/ssaraid.smit \ lstssaraid_raid_5_cmd_to_exec 'raid_5' | \ grep disk|awk '{print $2}'; \ echo "$(date) - $a bytes left ..."; \ sleep 60; \ done; \ while print -n '\a\a\a\a\a\a\a\a\a\a';do sleep 2;done ----------------------------------------------------------------------- See other examples in my /u/jasper/aixnotes/ksh_examples directory. ----------------------------------------------------------------------- To do something 10 times, try i=10 while (($i)) do ... ((i-=1)) # decrement count done ----------------------------------------------------------------------- To quickly & efficiently copy one complete directory structure from one directory into another, preserving most time stamps and owners, copies over links, etc (in other words, most of what you want), cd (cd ; tar -cvf - *) | tar -xvf - The owner information will be mostly correct, but links get your userid as the owner and new time stamps, so insure you're doing this as the owner you want (maybe, not root?). There's nothing you can do about the link time stamps. ----------------------------------------------------------------------- Here's a long command I worked on one day to count how many empty slots I had in the jukebox file, which looked like this # This is the inventory of CD's in the Image Server jukeboxes. # This file will be edited as new CD's are added. #Slot S1JB0 S1JB1 S2JB0 S2JB1 S3JB0 S3JB1 #==== ========== ========== ========== ========== ========== ========== 1 199501031 199501032 199501033 199501101 199501102 199501103 2 199502071 199502072 199502141 199502142 199502143 199502211 3 199503072 199503073 199503141 199503142 199503211 199503212 4 199504043 199504111 199504112 199504113 199504181 199504182 5 199505023 199505091 199505092 199505093 199505161 199505162 ... 500 --------- --------- --------- --------- --------- --------- The empty slots were designated by the dashes. This file is in ~jasper/bin/count-empty-jukebox-slots #!/bin/ksh a=/afs/alm/cs/datafactory/Pserver/docs/patimg.jukebox.database grep -v '^#' $a | # Get rid of comment lines grep -v '^$' | # Get rid of empty lines grep -- '---------' | # I only want lines with empties in them sed 's/.....//;s/ */ /g;s/^ *//;s/ /\^J/g' | --------- --------- -------- --------- \ \ \ \-- This changes all blanks into new-lines. \ \ \ The \^J is a backslash-enter, so don't \ \ \ just cut & paste this command. \ \ \-- This removes all leading blanks. \ \-- This changes multiple blanks to single blanks. \-- This removes the first 5 columns, the slot #. grep -- '---------' | # Finally, collect all empties, wc -l # And count them. ----------------------------------------------------------------------- To parse something in order to be able to act on fields within it, for example, a command produces a list of numbers and you want to add them up and print all the numbers & the total all on one line, try set -A answer $(/usr/lpp/ssp/bin/dsh "/usr/bin/wc -l /arc/httpd/logs/httpd-log.$thedate"\ | / usr/bin/awk '{print $2}') ((total=${answer[0]} + ${answer[1]} + ${answer[2]} + \ ${answer[3]} + ${answer[4]} + ${answer[5]} + \ ${answer[6]} + ${answer[7]} + ${answer[8]} + ${answer[9]} )) ----------------------------------------------------------------------- To parse up a bunch of options, use this, pulled from a smit.log while getopts N:t:P:T:n:h:a:l:r:C:c:E:U:k: FLAG do case $FLAG in N) NAME=$OPTARG;; t) TYPE=$OPTARG;; P) PLATFORM=$OPTARG;; T) CABLE=$OPTARG;; n) NETNAME=$OPTARG;; h) HOSTNAME=$OPTARG;; a) HADDR=$OPTARG;; l) ADAPTER=$OPTARG;; C) CPUID=$OPTARG;; c) COMMENTS=$OPTARG;; E) IPLROM_EMU=$OPTARG;; U) GROUP=$OPTARG;; k) NETBOOT_KERNEL=$OPTARG;; esac done Also, out of that same nimadd piece of code, was this tidbit. To output something only if a variable is set, use ${CPUID:+-a cpuid=$CPUID} which produces no output if $CPUID isn't set, but produces -a cpuid=$CPUID if it is. Notice that the above uses curly brackets, i.e. it's the ${parameter:+word} notation, as described in the Korn Shell book on page 173. ----------------------------------------------------------------------- To see if a variable contains a particular string, try if [[ $APSCONV_Parms = *(?)' -npo '*(?) ]] ... or if [[ $last_dates != [0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9] ]] then echo "The first argument must be a date, e.g. 07/18/2002" exit fi or to see if this is an interactive ksh (versus a ksh program), if [[ $- = *i* ]] # Are we running interactive? then /ips/tools/stayalive # Yes, keep alive. fi Background: $- is the ksh's invocation options echo $- displays ism, where i=interactive shell s=Read commands from STDIN m=Runs bg jobs in separate process ----------------------------------------------------------------------- Just because I had trouble finding it one day, this is the link in my online AIX notes, to the ksh pattern matching stuff. file:///C:/reference/aix4.3/aixuser/usrosdev/file_name_subst_korn_shell.htm#A56C21eeb It says in part, These pattern-matching characters indicate the following substitutions: * Matches any string, including the null string. ? Matches any single character. [...] Matches any one of the enclosed characters. A pair of characters separated by a - matches any character within the inclusive range of that pair. If the first character following the opening [ (left bracket) is an ! (exclamation point), then any character not enclosed is matched. A - (hyphen) can be included in the character set by putting it as the first or last character. A PatternList is a list of one or more patterns separated from each other with a vertical bar ( | ). Composite patterns are formed with one or more of the following: ?(PatternList) Optionally matches any one of the given patterns. *(PatternList) Matches zero or more occurrences of the given patterns. +(PatternList) Matches one or more occurrences of the given patterns. @(PatternList) Matches exactly one of the given patterns. !(PatternList) Matches anything, except one of the given patterns. If a pattern does not match any file names, then the pattern itself is returned as the result of the attempted match.