(M)  s i s t e m a   o p e r a c i o n a l   m a g n u x   l i n u x ~/ · documentação · suporte · sobre

 

3.29. Miscellany

 

Nobody really knows what the Bourne shell's grammar is. Even examination of the source code is little help.

 Tom Duff

3.29.1. Interactive and non-interactive scripts

Let us define an interactive script as one that requires input from the user, usually with read statements (see Example 3-42). "Real life" is actually a bit messier than that, and the formal specifications of an interactive shell (according to Ramey & Fox) are complex and confusing. For now, assume an interactive script is one that is bound to a tty, a script that a user has invoked from the console or an xterm.

Init and startup scripts are necessarily non-interactive, since they must run without human intervention. Many administrative and system maintenance scripts are likewise non-interactive. Unvarying repetitive tasks cry out for automation by non-interactive scripts.

Non-interactive scripts can run in the background, but interactive ones hang, waiting for input that never comes. Handle that difficulty by having an expect script or embedded here document (see Section 3.24) feed input to an interactive script running as a background job. In the simplest case, redirect a file to supply input to a read statement (read variable <file). These particular workarounds make possible general purpose scripts that run in either interactive or non-interactive modes.

If a script needs to test whether it is running in interactive mode, it is simply a matter of finding whether the prompt variable, $PS1 is set. (If the user is being prompted for input, then the script needs to display a prompt.)

if [ -z $PS1 ] # no prompt?
then
  # non-interactive
  ...
else
  # interactive
  ...
fi
Alternatively, the script can test for the presence of i in the $- flag.
case $- in
*i*)    # interactive script
;;
*)      # non-interactive script
;;
# (Thanks to "UNIX F.A.Q.", 1993)

Note: Scripts may be forced to run in interactive mode with the i option or with a #!/bin/bash -i header. Be aware that this may cause erratic script behavior or show error messages where no error is present.

3.29.2. Optimizations

Most shell scripts are quick 'n dirty solutions to non-complex problems. As such, optimizing them for speed is not much of an issue. Consider the case, though, where a script carries out an important task, does it well, but runs too slowly. Rewriting it in a compiled language may not be a palatable option. The simplest fix would be to rewrite the parts of the script that slow it down. Is it possible to apply principles of code optimization even to a lowly shell script?

Check the loops in the script. Time consumed by repetitive operations adds up quickly. Use the time and times tools to profile computation-intensive commands. Consider rewriting time-critical code sections in C, or even in assembler.

Try to minimize file i/o. Bash is not particularly efficient at handling files, so consider using more appropriate tools for this within the script, such as awk or Perl.

Try to write your scripts in a structured, coherent form, so they can be reorganized and tightened up as necessary. Some of the optimization techniques applicable to high-level languages may work for scripts, but others, such as loop unrolling, are mostly irrelevant. Above all, use common sense.

3.29.3. Assorted Tips

  • To keep a record of which user scripts have run during a particular sesssion or over a number of sessions, add the following lines to each script you want to keep track of. This will keep a continuing file record of the script names and invocation times.

    # Append (>>) following to end of save file.
    date>> $SAVE_FILE   #Date and time.
    echo $0>> $SAVE_FILE   #Script name.
    echo>> $SAVE_FILE   #Blank line as separator.
    # Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc
    # (something like ~/.scripts-run)

  • A shell script may act as an embedded command inside another shell script, a Tcl or wish script, or even a Makefile. It can be invoked as as an external shell command in a C program using the system() call, i.e., system("script_name");.

  • Put together a file of your favorite and most useful definitions and functions, then "include" this file in scripts as necessary with either the "dot" (.) or source command (see Section 3.2).

  • It would be nice to be able to invoke X-Windows widgets from a shell script. There do, in fact, exist a couple of packages that purport to do so, namely Xscript and Xmenu, but these seem to be pretty much defunct. If you dream of a script that can create widgets, try wish (a Tcl derivative), PerlTk (Perl with Tk extensions), or tksh (ksh with Tk extensions).