42
read inner_variable <$TMPFILE # Read back shell variable.
rm -f "$TMPFILE" # Get rid of temp file.
echo "$inner_variable" # It's an ugly kludge, but it works.
The run-parts command is handy for running a set of command scripts in a particular sequence,
especially in combination with cron or at.
•
For doing multiple revisions on a complex script, use the rcs Revision Control System package.
Among other benefits of this is automatically updated ID header tags. The co command in rcs does a
parameter replacement of certain reserved key words, for example, replacing # $Id$ in a script with
something like:
# $Id: hello-world.sh,v 1.1 2004/10/16 02:43:05 bozo Exp $
•
36.7.2. Widgets
It would be nice to be able to invoke X-Windows widgets from a shell script. There happen to exist several
packages that purport to do so, namely Xscript, Xmenu, and widtools. The first two of these no longer seem to
be maintained. Fortunately, it is still possible to obtain widtools here.
The widtools (widget tools) package requires the XForms library to be installed. Additionally, the
Makefile needs some judicious editing before the package will build on a typical Linux system. Finally,
three of the six widgets offered do not work (and, in fact, segfault).
The dialog family of tools offers a method of calling "dialog" widgets from a shell script. The original dialog
utility works in a text console, but its successors, gdialog, Xdialog, and kdialog use X-Windows-based widget
sets.
Example 36-22. Widgets invoked from a shell script
#!/bin/bash
# dialog.sh: Using 'gdialog' widgets.
# Must have 'gdialog' installed on your system to run this script.
# Or, you can replace all instance of 'gdialog' below with 'kdialog' ...
# Version 1.1 (corrected 04/05/05)
# This script was inspired by the following article.
# "Scripting for X Productivity," by Marco Fioretti,
# LINUX JOURNAL, Issue 113, September 2003, pp. 86-9.
# Thank you, all you good people at LJ.
# Input error in dialog box.
E_INPUT=85
# Dimensions of display, input widgets.
HEIGHT=50
WIDTH=60
# Output file name (constructed out of script name).
OUTFILE=$0.output
Advanced Bash-Scripting Guide
Chapter 36. Miscellany
539
41
# Display this script in a text widget.
gdialog --title "Displaying: $0" --textbox $0 $HEIGHT $WIDTH
# Now, we'll try saving input in a file.
echo -n "VARIABLE=" > $OUTFILE
gdialog --title "User Input" --inputbox "Enter variable, please:" \
$HEIGHT $WIDTH 2>> $OUTFILE
if [ "$?" -eq 0 ]
# It's good practice to check exit status.
then
echo "Executed \"dialog box\" without errors."
else
echo "Error(s) in \"dialog box\" execution."
# Or, clicked on "Cancel", instead of "OK" button.
rm $OUTFILE
exit $E_INPUT
fi
# Now, we'll retrieve and display the saved variable.
. $OUTFILE # 'Source' the saved file.
echo "The variable input in the \"input box\" was: "$VARIABLE""
rm $OUTFILE # Clean up by removing the temp file.
# Some applications may need to retain this file.
exit $?
# Exercise: Rewrite this script using the 'zenity' widget set.
The xmessage command is a simple method of popping up a message/query window. For example:
xmessage Fatal error in script! -button exit
The latest entry in the widget sweepstakes is zenity. This utility pops up GTK+ dialog widgets-and-windows,
and it works very nicely within a script.
get_info ()
{
zenity --entry # Pops up query window . . .
#+ and prints user entry to stdout.
# Also try the --calendar and --scale options.
}
answer=$( get_info ) # Capture stdout in $answer variable.
echo "User entered: "$answer""
For other methods of scripting with widgets, try Tk or wish (Tcl derivatives), PerlTk (Perl with Tk
extensions), tksh (ksh with Tk extensions), XForms4Perl (Perl with XForms extensions), Gtk-Perl (Perl with
Gtk extensions), or PyQt (Python with Qt extensions).
Advanced Bash-Scripting Guide
Chapter 36. Miscellany
540
38
36.8. Security Issues
36.8.1. Infected Shell Scripts
A brief warning about script security is indicated. A shell script may contain a worm, trojan, or even a virus.
For that reason, never run as root a script (or permit it to be inserted into the system startup scripts in
/etc/rc.d) unless you have obtained said script from a trusted source or you have carefully analyzed it to
make certain it does nothing harmful.
Various researchers at Bell Labs and other sites, including M. Douglas McIlroy, Tom Duff, and Fred Cohen
have investigated the implications of shell script viruses. They conclude that it is all too easy for even a
novice, a "script kiddie," to write one. [128]
Here is yet another reason to learn scripting. Being able to look at and understand scripts may protect your
system from being compromised by a rogue script.
36.8.2. Hiding Shell Script Source
For security purposes, it may be necessary to render a script unreadable. If only there were a utility to create a
stripped binary executable from a script. Francisco Rosales' shc -- generic shell script compiler does exactly
that.
Unfortunately, according to an article in the October, 2005 Linux Journal, the binary can, in at least some
cases, be decrypted to recover the original script source. Still, this could be a useful method of keeping scripts
secure from all but the most skilled hackers.
36.8.3. Writing Secure Shell Scripts
Dan Stromberg suggests the following guidelines for writing (relatively) secure shell scripts.
Don't put secret data in environment variables.
•
Don't pass secret data in an external command's arguments (pass them in via a pipe or redirection
instead).
•
Set your $PATH carefully. Don't just trust whatever path you inherit from the caller if your script is
running as root. In fact, whenever you use an environment variable inherited from the caller, think
about what could happen if the caller put something misleading in the variable, e.g., if the caller set
$HOME to /etc.
•
36.9. Portability Issues
It is easier to port a shell than a shell script.
--Larry Wall
This book deals specifically with Bash scripting on a GNU/Linux system. All the same, users of sh and ksh
will find much of value here.
Advanced Bash-Scripting Guide
Chapter 36. Miscellany
541
53
As it happens, many of the various shells and scripting languages seem to be converging toward the POSIX
1003.2 standard. Invoking Bash with the --posix option or inserting a set -o posix at the head of a script
causes Bash to conform very closely to this standard. Another alternative is to use a #!/bin/sh sha-bang header
in the script, rather than #!/bin/bash. [129] Note that /bin/sh is a link to /bin/bash in Linux and certain
other flavors of UNIX, and a script invoked this way disables extended Bash functionality.
Most Bash scripts will run as-is under ksh, and vice-versa, since Chet Ramey has been busily porting ksh
features to the latest versions of Bash.
On a commercial UNIX machine, scripts using GNU-specific features of standard commands may not work.
This has become less of a problem in the last few years, as the GNU utilities have pretty much displaced their
proprietary counterparts even on "big-iron" UNIX. Caldera's release of the source to many of the original
UNIX utilities has accelerated the trend.
Bash has certain features that the traditional Bourne shell lacks. Among these are:
Certain extended invocation options
•
Command substitution using $( ) notation
•
Brace expansion
•
Certain array operations, and associative arrays
•
The double brackets extended test construct
•
The double-parentheses arithmetic-evaluation construct
•
Certain string manipulation operations
•
Process substitution
•
A Regular Expression matching operator
•
Bash-specific builtins
•
Coprocesses
•
See the Bash F.A.Q. for a complete listing.
36.9.1. A Test Suite
Let us illustrate some of the incompatibilities between Bash and the classic Bourne shell. Download and
install the "Heirloom Bourne Shell" and run the following script, first using Bash, then the classic sh.
Example 36-23. Test Suite
#!/bin/bash
# test-suite.sh
# A partial Bash compatibility test suite.
# Run this on your version of Bash, or some other shell.
default_option=FAIL # Tests below will fail unless . . .
echo
echo -n "Testing "
sleep 1; echo -n ". "
sleep 1; echo -n ". "
sleep 1; echo ". "
echo
Advanced Bash-Scripting Guide
Chapter 36. Miscellany
542
46
# Double brackets
String="Double brackets supported?"
echo -n "Double brackets test: "
if [[ "$String" = "Double brackets supported?" ]]
then
echo "PASS"
else
echo "FAIL"
fi
# Double brackets and regex matching
String="Regex matching supported?"
echo -n "Regex matching: "
if [[ "$String" =~ R.....matching* ]]
then
echo "PASS"
else
echo "FAIL"
fi
# Arrays
test_arr=$default_option # FAIL
Array=( If supports arrays will print PASS )
test_arr=${Array[5]}
echo "Array test: $test_arr"
# Command Substitution
csub_test ()
{
echo "PASS"
}
test_csub=$default_option # FAIL
test_csub=$(csub_test)
echo "Command substitution test: $test_csub"
echo
# Completing this script is an exercise for the reader.
# Add to the above similar tests for double parentheses,
#+ brace expansion, process substitution, etc.
exit $?
36.10. Shell Scripting Under Windows
Even users running that other OS can run UNIX-like shell scripts, and therefore benefit from many of the
lessons of this book. The Cygwin package from Cygnus and the MKS utilities from Mortice Kern Associates
add shell scripting capabilities to Windows.
Another alternative is UWIN, written by David Korn of AT&T, of Korn Shell fame.
In 2006, Microsoft released the Windows Powershell®, which contains limited Bash-like command-line
scripting capabilities.
Advanced Bash-Scripting Guide
Chapter 36. Miscellany
543
37
Chapter 37. Bash, versions 2, 3, and 4
37.1. Bash, version 2
The current version of Bash, the one you have running on your machine, is most likely version 2.xx.yy,
3.xx.yy, or 4.xx.yy.
bash$ echo $BASH_VERSION
3.2.25(1)-release
The version 2 update of the classic Bash scripting language added array variables, string and parameter
expansion, and a better method of indirect variable references, among other features.
Example 37-1. String expansion
#!/bin/bash
# String expansion.
# Introduced with version 2 of Bash.
# Strings of the form $'xxx'
#+ have the standard escaped characters interpreted.
echo $'Ringing bell 3 times \a \a \a'
# May only ring once with certain terminals.
# Or ...
# May not ring at all, depending on terminal settings.
echo $'Three form feeds \f \f \f'
echo $'10 newlines \n\n\n\n\n\n\n\n\n\n'
echo $'\102\141\163\150'
# B a s h
# Octal equivalent of characters.
exit
Example 37-2. Indirect variable references - the new way
#!/bin/bash
# Indirect variable referencing.
# This has a few of the attributes of references in C++.
a=letter_of_alphabet
letter_of_alphabet=z
echo "a = $a" # Direct reference.
echo "Now a = ${!a}" # Indirect reference.
# The ${!variable} notation is more intuitive than the old
#+ eval var1=\$$var2
echo
Chapter 37. Bash, versions 2, 3, and 4
544
Documents you may be interested
Documents you may be interested