variables that affect the behavior of the shell and
user interface
In a more general context, each process has an
"environment", that is, a group of
variables that hold information that the process
may reference. In this sense, the shell behaves like
any other process.
Every time a shell starts, it creates shell variables that
correspond to its own environmental variables. Updating
or adding new environmental variables causes the shell
to update its environment, and all the shell's child
processes (the commands it executes) inherit this
environment.
The space allotted to the environment is limited.
Creating too many environmental variables or ones that use up
excessive space may cause problems.
bash$ eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"bash$ dubash: /usr/bin/du: Argument list too long
(Thank you, St�phane Chazelas for the clarification,
and for providing the above example.)
If a script sets environmental variables, they need to be
"exported", that is, reported to the
environment local to the script. This is the function of
the export command.
A script can export variables only
to child processes, that is, only to commands or processes
which that particular script initiates. A script invoked
from the command line cannot
export variables back to the command line environment.
Child processes cannot export
variables back to the parent processes that spawned
them.
---
positional parameters
arguments passed to the script from the command
line: $0, $1,
$2, $3 . . .
$0 is the name of the script itself,
$1 is the first argument,
$2 the second, $3
the third, and so forth.
[1]
After $9, the arguments must be enclosed
in brackets, for example, ${10},
${11}, ${12}.
The special variables $* and $@
denote all the positional parameters.
Example 4-5. Positional Parameters
#!/bin/bash
# Call this script with at least 10 parameters, for example
# ./scriptname 1 2 3 4 5 6 7 8 9 10
MINPARAMS=10
echo
echo "The name of this script is \"$0\"."
# Adds ./ for current directory
echo "The name of this script is \"`basename $0`\"."
# Strips out path name info (see 'basename')
echo
if [ -n "$1" ] # Tested variable is quoted.
then
echo "Parameter #1 is $1" # Need quotes to escape #
fi
if [ -n "$2" ]
then
echo "Parameter #2 is $2"
fi
if [ -n "$3" ]
then
echo "Parameter #3 is $3"
fi
# ...
if [ -n "${10}" ] # Parameters > $9 must be enclosed in {brackets}.
then
echo "Parameter #10 is ${10}"
fi
echo "-----------------------------------"
echo "All the command-line parameters are: "$*""
if [ $# -lt "$MINPARAMS" ]
then
echo
echo "This script needs at least $MINPARAMS command-line arguments!"
fi
echo
exit 0
Bracket notation for positional
parameters leads to a fairly simple way of referencing
the last argument passed to a
script on the command line. This also requires indirect referencing.
args=$# # Number of args passed.
lastarg=${!args}
# Or: lastarg=${!#}
# (Thanks, Chris Monson.)
# Note that lastarg=${!$#} doesn't work.
Some scripts can perform different operations,
depending on which name they are invoked with. For this
to work, the script needs to check $0,
the name it was invoked by. There must also exist symbolic
links to all the alternate names of the script. See Example 12-2.
If a script expects a command line parameter
but is invoked without one, this may cause a null variable
assignment, generally an undesirable result. One way to prevent
this is to append an extra character to both sides of the
assignment statement using the expected positional parameter.
variable1_=$1_ # Rather than variable1=$1
# This will prevent an error, even if positional parameter is absent.
critical_argument01=$variable1_
# The extra character can be stripped off later, like so.
variable1=${variable1_/_/}
# Side effects only if $variable1_ begins with an underscore.
# This uses one of the parameter substitution templates discussed later.
# (Leaving out the replacement pattern results in a deletion.)
# A more straightforward way of dealing with this is
#+ to simply test whether expected positional parameters have been passed.
if [ -z $1 ]
then
exit $E_MISSING_POS_PARAM
fi
# However, as Fabian Kreutz points out,
#+ the above method may have unexpected side-effects.
# A better method is parameter substitution:
# ${1:-$DefaultVal}
# See the "Parameter Substition" section
#+ in the "Variables Revisited" chapter.
#!/bin/bash
# ex18.sh
# Does a 'whois domain-name' lookup on any of 3 alternate servers:
# ripe.net, cw.net, radb.net
# Place this script -- renamed 'wh' -- in /usr/local/bin
# Requires symbolic links:
# ln -s /usr/local/bin/wh /usr/local/bin/wh-ripe
# ln -s /usr/local/bin/wh /usr/local/bin/wh-cw
# ln -s /usr/local/bin/wh /usr/local/bin/wh-radb
E_NOARGS=65
if [ -z "$1" ]
then
echo "Usage: `basename $0` [domain-name]"
exit $E_NOARGS
fi
# Check script name and call proper server.
case `basename $0` in # Or: case ${0##*/} in
"wh" ) whois [email protected];;
"wh-ripe") whois [email protected];;
"wh-radb") whois [email protected];;
"wh-cw" ) whois [email protected];;
* ) echo "Usage: `basename $0` [domain-name]";;
esac
exit $?
---
The shift command reassigns the positional
parameters, in effect shifting them to the left one notch.
$1 <--- $2, $2 <--- $3, $3 <--- $4, etc.
The old $1 disappears, but
$0 (the script name)
does not change. If you use a large number of
positional parameters to a script, shift
lets you access those past 10, although
{bracket} notation
also permits this.
Example 4-7. Using shift
#!/bin/bash
# Using 'shift' to step through all the positional parameters.
# Name this script something like shft,
#+ and invoke it with some parameters, for example
# ./shft a b c def 23 skidoo
until [ -z "$1" ] # Until all parameters used up...
do
echo -n "$1 "
shift
done
echo # Extra line feed.
exit 0
The shift command works in a similar
fashion on parameters passed to a function. See Example 33-15.