old-www/LDP/abs/html/othertypesv.html

1134 lines
17 KiB
HTML
Raw Permalink Blame History

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Special Variable Types</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Advanced Bash-Scripting Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Introduction to Variables and Parameters"
HREF="variables.html"><LINK
REL="PREVIOUS"
TITLE="Bash Variables Are Untyped"
HREF="untyped.html"><LINK
REL="NEXT"
TITLE="Quoting"
HREF="quoting.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Advanced Bash-Scripting Guide: </TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="untyped.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 4. Introduction to Variables and Parameters</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="quoting.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="OTHERTYPESV"
></A
>4.4. Special Variable Types</H1
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
><TT
CLASS="REPLACEABLE"
><I
>Local variables</I
></TT
></DT
><DD
><P
>Variables <A
HREF="subshells.html#SCOPEREF"
>visible</A
> only within a <A
HREF="special-chars.html#CODEBLOCKREF"
>code block</A
> or function (see
also <A
HREF="localvar.html#LOCALREF"
>local variables</A
> in
<A
HREF="functions.html#FUNCTIONREF"
>functions</A
>)</P
></DD
><DT
><A
NAME="ENVREF"
></A
><TT
CLASS="REPLACEABLE"
><I
>Environmental variables</I
></TT
></DT
><DD
><P
>Variables that affect the behavior of the shell and
user interface</P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>In a more general context, each <A
HREF="special-chars.html#PROCESSREF"
>process</A
> has an
<SPAN
CLASS="QUOTE"
>"environment"</SPAN
>, that is, a group of
variables that the process may reference. In this sense,
the shell behaves like any other process.</P
><P
>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
<I
CLASS="FIRSTTERM"
>child processes</I
> (the commands it
executes) inherit this environment.</P
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The space allotted to the environment is limited.
Creating too many environmental variables or ones that use up
excessive space may cause problems.</P
><P
> <TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
><TT
CLASS="PROMPT"
>bash$ </TT
><TT
CLASS="USERINPUT"
><B
>eval "`seq 10000 | sed -e 's/.*/export var&#38;=ZZZZZZZZZZZZZZ/'`"</B
></TT
>
<TT
CLASS="PROMPT"
>bash$ </TT
><TT
CLASS="USERINPUT"
><B
>du</B
></TT
>
<TT
CLASS="COMPUTEROUTPUT"
>bash: /usr/bin/du: Argument list too long</TT
>
</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
>Note: this <SPAN
CLASS="QUOTE"
>"error"</SPAN
> has been fixed, as of
kernel version 2.6.23.</P
><P
>(Thank you, St<53>phane Chazelas for the clarification,
and for providing the above example.)</P
></TD
></TR
></TABLE
></DIV
><P
>If a script sets environmental variables, they need to be
<SPAN
CLASS="QUOTE"
>"exported,"</SPAN
> that is, reported to the
<I
CLASS="FIRSTTERM"
>environment</I
> local to
the script. This is the function of the <A
HREF="internal.html#EXPORTREF"
>export</A
> command.</P
><A
NAME="CHILDREF"
></A
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>A script can <B
CLASS="COMMAND"
>export</B
> variables only
to child <A
HREF="special-chars.html#PROCESSREF"
>processes</A
>,
that is, only to commands or processes which that
particular script initiates. A script invoked from
the command-line <TT
CLASS="REPLACEABLE"
><I
>cannot</I
></TT
>
export variables back to the command-line environment.
<EM
><A
HREF="internal.html#FORKREF"
>Child processes</A
>
cannot export variables back to the parent processes that
spawned them.</EM
></P
><P
><A
NAME="CHILDREF2"
></A
><TT
CLASS="USERINPUT"
><B
>Definition:</B
></TT
>
A <I
CLASS="FIRSTTERM"
>child process</I
> is a
subprocess launched by another process, its <A
HREF="internal.html#PARENTREF"
>parent</A
>.</P
></TD
></TR
></TABLE
></DIV
></DD
><DT
><A
NAME="POSPARAMREF1"
></A
><TT
CLASS="REPLACEABLE"
><I
>Positional parameters</I
></TT
></DT
><DD
><P
>Arguments passed to the script from the command
line
<A
NAME="AEN2450"
HREF="#FTN.AEN2450"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
>
: <TT
CLASS="VARNAME"
>$0</TT
>, <TT
CLASS="VARNAME"
>$1</TT
>,
<TT
CLASS="VARNAME"
>$2</TT
>, <TT
CLASS="VARNAME"
>$3</TT
> . . .</P
><P
><A
NAME="SCRNAMEPARAM"
></A
><TT
CLASS="VARNAME"
>$0</TT
> is
the name of the script itself,
<TT
CLASS="VARNAME"
>$1</TT
> is the first argument,
<TT
CLASS="VARNAME"
>$2</TT
> the second, <TT
CLASS="VARNAME"
>$3</TT
>
the third, and so forth.
<A
NAME="AEN2464"
HREF="#FTN.AEN2464"
><SPAN
CLASS="footnote"
>[2]</SPAN
></A
>
<A
NAME="BRACKETNOTATION"
></A
>
After <TT
CLASS="VARNAME"
>$9</TT
>, the arguments must be enclosed
in brackets, for example, <TT
CLASS="VARNAME"
>${10}</TT
>,
<TT
CLASS="VARNAME"
>${11}</TT
>, <TT
CLASS="VARNAME"
>${12}</TT
>.</P
><P
>The special variables <A
HREF="internalvariables.html#APPREF"
>$* and $@</A
>
denote <EM
>all</EM
> the positional parameters.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX17"
></A
><P
><B
>Example 4-5. Positional Parameters</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/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 &#62; $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</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
><I
CLASS="FIRSTTERM"
>Bracket notation</I
> for positional
parameters leads to a fairly simple way of referencing
the <EM
>last</EM
> argument passed to a
script on the command-line. This also requires <A
HREF="bashver2.html#VARREFNEW"
>indirect referencing</A
>.</P
><P
><A
NAME="LASTARGREF"
></A
></P
><P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>args=$# # Number of args passed.
lastarg=${!args}
# Note: This is an *indirect reference* to $args ...
# Or: lastarg=${!#} (Thanks, Chris Monson.)
# This is an *indirect reference* to the $# variable.
# Note that lastarg=${!$#} doesn't work.</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>Some scripts can perform different operations,
depending on which name they are invoked with. For this
to work, the script needs to check <TT
CLASS="VARNAME"
>$0</TT
>,
the name it was invoked by.
<A
NAME="AEN2501"
HREF="#FTN.AEN2501"
><SPAN
CLASS="footnote"
>[3]</SPAN
></A
>
There must also exist symbolic links to all the alternate
names of the script. See <A
HREF="basic.html#HELLOL"
>Example 16-2</A
>.</P
><P
><A
NAME="NULLVAR"
></A
></P
><DIV
CLASS="TIP"
><P
></P
><TABLE
CLASS="TIP"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/tip.gif"
HSPACE="5"
ALT="Tip"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>If a script expects a command-line parameter
but is invoked without one, this may cause a <I
CLASS="FIRSTTERM"
>null
variable assignment</I
>, 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. </P
></TD
></TR
></TABLE
></DIV
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>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.</PRE
></FONT
></TD
></TR
></TABLE
><P
>---</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX18"
></A
><P
><B
>Example 4-6. <I
CLASS="FIRSTTERM"
>wh</I
>, <I
CLASS="FIRSTTERM"
> whois</I
> domain name lookup</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/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-apnic
# ln -s /usr/local/bin/wh /usr/local/bin/wh-tucows
E_NOARGS=75
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 $1@whois.tucows.com;;
"wh-ripe" ) whois $1@whois.ripe.net;;
"wh-apnic" ) whois $1@whois.apnic.net;;
"wh-cw" ) whois $1@whois.cw.net;;
* ) echo "Usage: `basename $0` [domain-name]";;
esac
exit $?</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>---</P
><P
><A
NAME="SHIFTREF"
></A
></P
><P
>
The <B
CLASS="COMMAND"
>shift</B
> command reassigns the positional
parameters, in effect shifting them to the left one notch.</P
><P
><TT
CLASS="VARNAME"
>$1</TT
> &#60;--- <TT
CLASS="VARNAME"
>$2</TT
>, <TT
CLASS="VARNAME"
>$2</TT
> &#60;--- <TT
CLASS="VARNAME"
>$3</TT
>, <TT
CLASS="VARNAME"
>$3</TT
> &#60;--- <TT
CLASS="VARNAME"
>$4</TT
>, etc.</P
><P
>The old <TT
CLASS="VARNAME"
>$1</TT
> disappears, but
<EM
><TT
CLASS="VARNAME"
>$0</TT
> (the script name)
does not change</EM
>. If you use a large number of
positional parameters to a script, <B
CLASS="COMMAND"
>shift</B
>
lets you access those past <TT
CLASS="LITERAL"
>10</TT
>, although
<A
HREF="othertypesv.html#BRACKETNOTATION"
>{bracket} notation</A
>
also permits this.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX19"
></A
><P
><B
>Example 4-7. Using <I
CLASS="FIRSTTERM"
>shift</I
></B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# shft.sh: Using 'shift' to step through all the positional parameters.
# Name this script something like shft.sh,
#+ and invoke it with some parameters.
#+ For example:
# sh shft.sh a b c def 83 barndoor
until [ -z "$1" ] # Until all parameters used up . . .
do
echo -n "$1 "
shift
done
echo # Extra linefeed.
# But, what happens to the "used-up" parameters?
echo "$2"
# Nothing echoes!
# When $2 shifts into $1 (and there is no $3 to shift into $2)
#+ then $2 remains empty.
# So, it is not a parameter *copy*, but a *move*.
exit
# See also the echo-params.sh script for a "shiftless"
#+ alternative method of stepping through the positional params.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>The <B
CLASS="COMMAND"
>shift</B
> command can take a numerical
parameter indicating how many positions to shift.</P
><P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# shift-past.sh
shift 3 # Shift 3 positions.
# n=3; shift $n
# Has the same effect.
echo "$1"
exit 0
# ======================== #
$ sh shift-past.sh 1 2 3 4 5
4
# However, as Eleni Fragkiadaki, points out,
#+ attempting a 'shift' past the number of
#+ positional parameters ($#) returns an exit status of 1,
#+ and the positional parameters themselves do not change.
# This means possibly getting stuck in an endless loop. . . .
# For example:
# until [ -z "$1" ]
# do
# echo -n "$1 "
# shift 20 # If less than 20 pos params,
# done #+ then loop never ends!
#
# When in doubt, add a sanity check. . . .
# shift 20 || break
# ^^^^^^^^</PRE
></FONT
></TD
></TR
></TABLE
></P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The <B
CLASS="COMMAND"
>shift</B
> command works in a similar
fashion on parameters passed to a <A
HREF="functions.html#FUNCTIONREF"
>function</A
>. See <A
HREF="assortedtips.html#MULTIPLICATION"
>Example 36-18</A
>.</P
></TD
></TR
></TABLE
></DIV
></DD
></DL
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN2450"
HREF="othertypesv.html#AEN2450"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>Note that <A
HREF="complexfunct.html#PASSEDARGS"
><I
CLASS="FIRSTTERM"
>functions</I
>
also take positional parameters</A
>.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN2464"
HREF="othertypesv.html#AEN2464"
><SPAN
CLASS="footnote"
>[2]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
><A
NAME="ARG0"
></A
>The process calling the
script sets the <TT
CLASS="VARNAME"
>$0</TT
> parameter. By
convention, this parameter is the name of the script. See
the <A
HREF="basic.html#MANREF"
>manpage</A
> (manual page)
for <B
CLASS="COMMAND"
>execv</B
>.</P
><P
>From the <I
CLASS="FIRSTTERM"
>command-line</I
>, however,
<TT
CLASS="VARNAME"
>$0</TT
> is the name of the shell.
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
><TT
CLASS="PROMPT"
>bash$ </TT
><TT
CLASS="USERINPUT"
><B
>echo $0</B
></TT
>
<TT
CLASS="COMPUTEROUTPUT"
>bash</TT
>
<TT
CLASS="PROMPT"
>tcsh% </TT
><TT
CLASS="USERINPUT"
><B
>echo $0</B
></TT
>
<TT
CLASS="COMPUTEROUTPUT"
>tcsh</TT
></PRE
></FONT
></TD
></TR
></TABLE
></P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN2501"
HREF="othertypesv.html#AEN2501"
><SPAN
CLASS="footnote"
>[3]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>If the the script is <A
HREF="internal.html#SOURCEREF"
>sourced</A
> or <A
HREF="basic.html#SYMLINKREF"
>symlinked</A
>, then
this will not work. It is safer to check <A
HREF="debugging.html#BASHSOURCEREF"
>$BASH_Source</A
>.</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="untyped.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="quoting.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Bash Variables Are Untyped</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="variables.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Quoting</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>