#! /bin/sh ############################################################ # This shell script is a "front-end" to 2body which # expedites the analysis of the results from that code, # including the generation of Postscript plots of the # particle position, d(energy), d(angular momentum) as a # function of time using gnuplot. # # The script is also intended as a general illustration of # shell programming. A key idea here is that many things # which are cumbersome in Fortran (or C, or C++) # (such as file manipulation, and piecing together different # commands) are easily accomplished with a script. # # See the Unix Programming Environment by Kernighan and Pike # for classic documentation on shell programming and more! ############################################################ ############################################################ # Note that the first line of this file is very important. # It allows Unix to identify the contents of the file as # a shell script ('/bin/sh' is the shell executable on # ALL non-brain-dead Unix systems), so that, provided the # file is made executable and resides in a directory in # the current path, typing the name of the file will # result in execution of the script. The space between # the '#!' and '/bin/sh'is recommended for maximum script # portability. # # A variant initial line, particularly useful for script # development is # # #! /bin/sh -x # # The '-x' flag enables tracing, so that assignments of # shell variables, execution of commands etc. will be # echoed to standard error. ############################################################ ############################################################ # ASSIGNMENT STATEMENTS # # The following code assigns some default values to some # shell variables. # # NOTE: There can be *no* white # space around the '=' in an assignment statement. If, # for example you type # # tmax = 5.0 # # then, when you execute the script, you will get the # cryptic error message # # tmax: Not found # # since the shell will be interpreting the line as the # *command* 'tmax' with arguments '= 5.0'. ############################################################ tmax=5.0 dt=0.05 tol=1.0d-6 ############################################################ # FUNCTIONS # # Usage function (subroutine). Illustrates one way to # "do usage" in shell script (using 'cat' plus a # "here document"), as well as the useful "here document" # construction. # # Here documents can be used anywhere # in a shell script (and in C-shell, Korn-shell, perl etc. # script) to provide "in-place" input for the standard input # of a command. You can refer to the man page on 'sh' # for full details, but the idea and mechanics are # simple. To provide "in-place" input to an arbitrary # command, append '<<END' after the command name and # all arguments. Be certain that there is no white # space between the '<<' and 'END' or after 'END'. # Subsequent lines are then the standard input to # the command. A line which *exactly* matches # the string 'END' (i.e. 'grep ^END$' succeeds) # signals end-of-file (so be sure you have such a line # in your script!). Again, beware of leading or trailing # white space in the end-of-file marker. Finally, note that # the string'END' is arbitrary---you can use essentially any # string you wish (but be sure to use the identical string in # both contexts)---'END' is simply my convention. # # Here documents wouldn't be half as interesting if # it weren't for the fact that they are partially interpreted # by the shell. In particular, shell variables are evaluated # as are `command [arguments]` constructs (recall that # we can view such constructs as "active expressions" of # their standard outputs). Thus, when the Usage subroutine # executes `date` will be replaced by the output from the # 'date' command and $tol will be replaced with the # specific value assigned above. ############################################################ Usage() { cat<<END `date` usage: Doit <y0> [<tol>] Default tol: $tol y0 = 1.0 will produce circular orbit. To enable automatic previewing of Postscript files set GV environment variable to any non-blank value, e.g. setenv GV on END ############################################################ # Exit with non-zero status (failure). ############################################################ exit 1 } ############################################################ # Subroutine (fcn) to produce postscript version of # gnuplot plot of data stored in file $1. Postscript # file will be called $1.ps. If optional second argument # is supplied, the resulting Postscript file will be # 'gv'ed. Again, note use of "here document"; # indentation of "here document" is strictly for readability. ############################################################ gnuplot_it(){ gnuplot<<END set terminal postscript portrait set size 0.760,1.0 set xlabel "x" set ylabel "$1" set output "$1.ps" plot "$1" quit END ############################################################ # IF STATEMENTS # # The following is shell-mnemonic for "if the second # argument exists". Note that the shell 'if' statement # is of the form # # if list then list [ elif list then list ] ... [ else list ] fi # # where a 'list' is a sequence of pipelines separated by ;, # &, # &&, or ||, and optionally terminated by ; or &. # 'list' is executed, and if it returns a zero exit # status (normal return), the 'list' following 'then' # is executed, otherwise the 'list' following 'elif' # is executed---if *it* returns a zero exit status, the # 'list' following the next 'then' is executed etc. # # A particularly useful command to use with a shell 'if' # is 'test', which has usage # # test expr # # or # # [ expr ] # # Note that '[' and ']' really ARE commands on a Unix system. # (Try 'which \['). Both forms of the command evaluate # 'expr' (which can contain various logical operators # and tests---see 'man test' for more information) as # a Boolean, returning 0 if the value is true and non-zero # otherwise. ############################################################ if test "${2}undefined" != undefined; then ############################################################ # Illustrates alternate (and less portable, so it is # claimed) form of 'test' ############################################################ if [ -f $1.ps ]; then (gv $1.ps) & else echo "gnuplot_it: $f.ps does not exist" fi fi } ############################################################ # ARGUMENT HANDLING and CASE STATEMENT # # '$#' is a special shell variable which evaluates to # the number of arguments supplied to the script. Each # clause in a case statment is of the form # # pattern [ | pattern ]...) list;; # # where each pattern is used for 'grep-style' pattern # matching against the case variable. In this case # we simply match against valid numbers of arguments # (1, 2 or 3), but note that the pattern-matching basis # of the case statement makes it a particularly powerful # and useful construct. Commands may be separated by # semicolons and/or new-lines. '*)' is a mnemonic for # 'default clause' and must come LAST in the case # enumeration, since matching is done clause by # clause until a match is found. # # Note that arguments to the script are available in # the special variables '1, 2, 3 ...'---i.e. # # y0=$1 # # assigns the first argument supplied to the script to # the shell variable 'y0' (The special vbl. # '0' stores the name of the script). Also note # the mnemonic typified by # # tol=${2-$tol} # # which reads "assign the second script argument to tol, # with a default value of $tol should the argument not # exist". ############################################################ case $# in 1|2) y0=$1; tol=${2-$tol};; *) Usage;; esac ############################################################ # Make sure the program has been compiled. ############################################################ make -f Makefile 2body ############################################################ # Create a 'tag' which identifies the computation (encodes # 'y0' and 'tol'), and use it to create the name of the # file to which '2body' output will be directed. Note # that the script does NOT completely clean up after itself # in the sense that the output file 'oute_...' is not # removed. ############################################################ tag="$y0"_"$tol" ofile=oute_"$tag" ############################################################ # Run the program and save the output in $ofile. ############################################################ 2body 0.0 $y0 1.0 0.0 $tmax $dt $tol > $ofile ############################################################ # Use 'nth' to create two column data files for as follows # # xcyc_$tag: xc yc # xc_$tag: t xc # yc_$tag: t yc # dEtot_$tag t dEtot # dJtot_$tag t JEtot ############################################################ nth 2 3 < $ofile > xcyc_$tag nth 1 2 < $ofile > xc_$tag nth 1 3 < $ofile > yc_$tag nth 1 4 < $ofile > dEtot_$tag nth 1 5 < $ofile > dJtot_$tag ############################################################ # FOR LOOPS # # General form: # # for name [ in word ... ] do list done # # In the case below, the shell variable 'f' takes on, # successively, the values, xcyc_$tag, xc_$tag, ... # # Note the semi-colon between the iteration values and the # 'do' keyword (a new-line will also work), and that 'done' # terminates the loop. ############################################################ for f in xcyc_$tag xc_$tag yc_$tag dEtot_$tag dJtot_$tag; do ############################################################ # Shell scripts inherit all environment variables, such # as 'GV'. If 'GV' has not been set in # the invoking environment, '$GV' will evaluate to # the null string. ############################################################ gnuplot_it $f $GV /bin/rm $f done /bin/ls -l *$tag*.ps ############################################################ # Normal exit (success) ############################################################ exit 0