| | Turandot: Gli enigmi sono tre, la morte una! Caleph: No, no! Gli enigmi sono tre, una la vita! |
| | Puccini |
Assigning reserved words or characters to variable names.
case=value0 # Causes problems.
23skidoo=value1 # Also problems.
# Variable names starting with a digit are reserved by the shell.
# Try _23skidoo=value1. Starting variables with an underscore is o.k.
# However... using just the underscore will not work.
_=25
echo $_ # $_ is a special variable set to last arg of last command.
xyz((!*=value2 # Causes severe problems. |
Using a hyphen or other reserved characters in a variable name.
var-1=23
# Use 'var_1' instead. |
Using the same name for a variable and a function. This can make a
script difficult to understand.
do_something ()
{
echo "This function does something with \"$1\"."
}
do_something=do_something
do_something do_something
# All this is legal, but highly confusing. |
Using whitespace inappropriately
(in contrast to other programming languages, Bash can be quite
finicky about whitespace).
var1 = 23 # 'var1=23' is correct.
# On line above, Bash attempts to execute command "var1"
# with the arguments "=" and "23".
let c = $a - $b # 'let c=$a-$b' or 'let "c = $a - $b"' are correct.
if [ $a -le 5] # if [ $a -le 5 ] is correct.
# if [ "$a" -le 5 ] is even better.
# [[ $a -le 5 ]] also works. |
Assuming uninitialized variables (variables before a value is
assigned to them) are "zeroed out". An
uninitialized variable has a value of "null",
not zero.
Mixing up = and -eq in
a test. Remember, = is for comparing literal
variables and -eq for integers.
if [ "$a" = 273 ] # Is $a an integer or string?
if [ "$a" -eq 273 ] # If $a is an integer.
# Sometimes you can mix up -eq and = without adverse consequences.
# However...
a=273.0 # Not an integer.
if [ "$a" = 273 ]
then
echo "Comparison works."
else
echo "Comparison does not work."
fi # Comparison does not work.
# Same with a=" 273" and a="0273".
# Likewise, problems trying to use "-eq" with non-integer values.
if [ "$a" -eq 273.0 ]
then
echo "a = $a'
fi # Aborts with an error message.
# test.sh: [: 273.0: integer expression expected |
Mixing up integer and
string comparison operators.
#!/bin/bash
# bad-op.sh
number=1
while [ "$number" < 5 ] # Wrong! Should be while [ "number" -lt 5 ]
do
echo -n "$number "
let "number += 1"
done
# Attempt to run this bombs with the error message:
# bad-op.sh: 5: No such file or directory |
Sometimes variables within "test" brackets
([ ]) need to be quoted (double quotes). Failure to do so may
cause unexpected behavior. See Example 7-5, Example 16-4, and Example 9-6.
Commands issued from a script may fail to execute because
the script owner lacks execute permission for them. If a user
cannot invoke a command from the command line, then putting it
into a script will likewise fail. Try changing the attributes of
the command in question, perhaps even setting the suid bit
(as root, of course).
Attempting to use - as a redirection
operator (which it is not) will usually result in an unpleasant
surprise.
command1 2> - | command2 # Trying to redirect error output of command1 into a pipe...
# ...will not work.
command1 2>& - | command2 # Also futile.
Thanks, S.C. |
Using Bash version 2+
functionality may cause a bailout with error messages. Older
Linux machines may have version 1.XX of Bash as the default
installation.
#!/bin/bash
minimum_version=2
# Since Chet Ramey is constantly adding features to Bash,
# you may set $minimum_version to 2.XX, or whatever is appropriate.
E_BAD_VERSION=80
if [ "$BASH_VERSION" \< "$minimum_version" ]
then
echo "This script works only with Bash, version $minimum or greater."
echo "Upgrade strongly recommended."
exit $E_BAD_VERSION
fi
... |
Using Bash-specific functionality in a Bourne shell script
(#!/bin/sh) on a non-Linux machine
may cause unexpected behavior. A Linux system usually aliases
sh to bash, but this does
not necessarily hold true for a generic UNIX machine.
A script with DOS-type newlines (\r\n)
will fail to execute, since #!/bin/bash\r\n
is not recognized, not the same as the
expected #!/bin/bash\n. The fix is to
convert the script to UNIX-style newlines.
A shell script headed by #!/bin/sh
may not run in full Bash-compatibility mode. Some Bash-specific
functions might be disabled. Scripts that need complete
access to all the Bash-specific extensions should start with
#!/bin/bash.
A script may not export variables back
to its parent process, the shell,
or to the environment. Just as we learned in biology, a child
process can inherit from a parent, but not vice versa.
WHATEVER=/home/bozo
export WHATEVER
exit 0 |
bash$ echo $WHATEVER
bash$ |
Sure enough, back at the command prompt, $WHATEVER remains unset.
Setting and manipulating variables in a subshell, then attempting
to use those same variables outside the scope of the subshell will
result an unpleasant surprise.
Example 32-1. Subshell Pitfalls
#!/bin/bash
# Pitfalls of variables in a subshell.
outer_variable=outer
echo
echo "outer_variable = $outer_variable"
echo
(
# Begin subshell
echo "outer_variable inside subshell = $outer_variable"
inner_variable=inner # Set
echo "inner_variable inside subshell = $inner_variable"
outer_variable=inner # Will value change globally?
echo "outer_variable inside subshell = $outer_variable"
# End subshell
)
echo
echo "inner_variable outside subshell = $inner_variable" # Unset.
echo "outer_variable outside subshell = $outer_variable" # Unchanged.
echo
exit 0 |
Piping
echooutput to a read may produce unexpected
results. In this scenario, the read
acts as if it were running in a subshell. Instead, use
the set command (as in Example 11-12).
Example 32-2. Piping the output of echo to a read
#!/bin/bash
# badread.sh:
# Attempting to use 'echo and 'read'
#+ to assign variables non-interactively.
a=aaa
b=bbb
c=ccc
echo "one two three" | read a b c
# Try to reassign a, b, and c.
echo
echo "a = $a" # a = aaa
echo "b = $b" # b = bbb
echo "c = $c" # c = ccc
# Reassignment failed.
# ------------------------------
# Try the following alternative.
var=`echo "one two three"`
set -- $var
a=$1; b=$2; c=$3
echo "-------"
echo "a = $a" # a = one
echo "b = $b" # b = two
echo "c = $c" # c = three
# Reassignment succeeded.
# ------------------------------
# Note also that an echo to a 'read' works within a subshell.
# However, the value of the variable changes *only* within the subshell.
a=aaa # Starting all over again.
b=bbb
c=ccc
echo; echo
echo "one two three" | ( read a b c;
echo "Inside subshell: "; echo "a = $a"; echo "b = $b"; echo "c = $c" )
# a = one
# b = two
# c = three
echo "-----------------"
echo "Outside subshell: "
echo "a = $a" # a = aaa
echo "b = $b" # b = bbb
echo "c = $c" # c = ccc
echo
exit 0 |
Using "suid" commands within scripts is risky,
as it may compromise system security.
[1]
Using shell scripts for CGI programming may be problematic. Shell
script variables are not "typesafe", and this can cause
undesirable behavior as far as CGI is concerned. Moreover, it is
difficult to "cracker-proof" shell scripts.
Bash scripts written for Linux or BSD systems may need
fixups to run on a commercial UNIX machine. Such scripts
often employ GNU commands and filters which have greater
functionality than their generic UNIX counterparts. This is
particularly true of such text processing utilites as tr.
| | Danger is near thee -- Beware, beware, beware, beware. Many brave hearts are asleep in the deep. So beware -- Beware. |
| | A.J. Lamb and H.W. Petrie |