1973 lines
33 KiB
HTML
1973 lines
33 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Bash, version 4</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="Bash, versions 2, 3, and 4"
|
|
HREF="bash2.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Bash, version 3"
|
|
HREF="bashver3.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Endnotes"
|
|
HREF="endnotes.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="bashver3.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Chapter 37. Bash, versions 2, 3, and 4</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="endnotes.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECT1"
|
|
><H1
|
|
CLASS="SECT1"
|
|
><A
|
|
NAME="BASHVER4"
|
|
></A
|
|
>37.3. Bash, version 4</H1
|
|
><P
|
|
><A
|
|
NAME="BASH4REF"
|
|
></A
|
|
></P
|
|
><P
|
|
>Chet Ramey announced Version 4 of Bash on the 20th
|
|
of February, 2009. This release has a number of significant
|
|
new features, as well as some important bugfixes.</P
|
|
><P
|
|
>Among the new goodies:</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="ASSOCARR"
|
|
></A
|
|
>Associative arrays.
|
|
<A
|
|
NAME="AEN21025"
|
|
HREF="#FTN.AEN21025"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[1]</SPAN
|
|
></A
|
|
>
|
|
</P
|
|
><TABLE
|
|
CLASS="SIDEBAR"
|
|
BORDER="1"
|
|
CELLPADDING="5"
|
|
><TR
|
|
><TD
|
|
><DIV
|
|
CLASS="SIDEBAR"
|
|
><A
|
|
NAME="AEN21029"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
>An <I
|
|
CLASS="FIRSTTERM"
|
|
>associative</I
|
|
> array can
|
|
be thought of as a set of two linked arrays -- one holding
|
|
the <I
|
|
CLASS="FIRSTTERM"
|
|
>data</I
|
|
>, and the other the
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>keys</I
|
|
> that index the individual elements
|
|
of the <I
|
|
CLASS="FIRSTTERM"
|
|
>data</I
|
|
> array.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="FETCHADDRESS"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-5. A simple address database</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
# fetch_address.sh
|
|
|
|
declare -A address
|
|
# -A option declares associative array.
|
|
|
|
address[Charles]="414 W. 10th Ave., Baltimore, MD 21236"
|
|
address[John]="202 E. 3rd St., New York, NY 10009"
|
|
address[Wilma]="1854 Vermont Ave, Los Angeles, CA 90023"
|
|
|
|
|
|
echo "Charles's address is ${address[Charles]}."
|
|
# Charles's address is 414 W. 10th Ave., Baltimore, MD 21236.
|
|
echo "Wilma's address is ${address[Wilma]}."
|
|
# Wilma's address is 1854 Vermont Ave, Los Angeles, CA 90023.
|
|
echo "John's address is ${address[John]}."
|
|
# John's address is 202 E. 3rd St., New York, NY 10009.
|
|
|
|
echo
|
|
|
|
echo "${!address[*]}" # The array indices ...
|
|
# Charles John Wilma</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="FETCHADDRESS2"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-6. A somewhat more elaborate address database</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
# fetch_address-2.sh
|
|
# A more elaborate version of fetch_address.sh.
|
|
|
|
SUCCESS=0
|
|
E_DB=99 # Error code for missing entry.
|
|
|
|
declare -A address
|
|
# -A option declares associative array.
|
|
|
|
|
|
store_address ()
|
|
{
|
|
address[$1]="$2"
|
|
return $?
|
|
}
|
|
|
|
|
|
fetch_address ()
|
|
{
|
|
if [[ -z "${address[$1]}" ]]
|
|
then
|
|
echo "$1's address is not in database."
|
|
return $E_DB
|
|
fi
|
|
|
|
echo "$1's address is ${address[$1]}."
|
|
return $?
|
|
}
|
|
|
|
|
|
store_address "Lucas Fayne" "414 W. 13th Ave., Baltimore, MD 21236"
|
|
store_address "Arvid Boyce" "202 E. 3rd St., New York, NY 10009"
|
|
store_address "Velma Winston" "1854 Vermont Ave, Los Angeles, CA 90023"
|
|
# Exercise:
|
|
# Rewrite the above store_address calls to read data from a file,
|
|
#+ then assign field 1 to name, field 2 to address in the array.
|
|
# Each line in the file would have a format corresponding to the above.
|
|
# Use a while-read loop to read from file, sed or awk to parse the fields.
|
|
|
|
fetch_address "Lucas Fayne"
|
|
# Lucas Fayne's address is 414 W. 13th Ave., Baltimore, MD 21236.
|
|
fetch_address "Velma Winston"
|
|
# Velma Winston's address is 1854 Vermont Ave, Los Angeles, CA 90023.
|
|
fetch_address "Arvid Boyce"
|
|
# Arvid Boyce's address is 202 E. 3rd St., New York, NY 10009.
|
|
fetch_address "Bozo Bozeman"
|
|
# Bozo Bozeman's address is not in database.
|
|
|
|
exit $? # In this case, exit code = 99, since that is function return.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>See <A
|
|
HREF="contributed-scripts.html#SAMORSE"
|
|
>Example A-53</A
|
|
> for an interesting
|
|
usage of an <I
|
|
CLASS="FIRSTTERM"
|
|
>associative array</I
|
|
>.</P
|
|
><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
|
|
>Elements of the <I
|
|
CLASS="FIRSTTERM"
|
|
>index</I
|
|
> array
|
|
may include embedded <A
|
|
HREF="special-chars.html#WHITESPACEREF"
|
|
>space
|
|
characters</A
|
|
>, or even leading and/or trailing space
|
|
characters. However, index array elements containing
|
|
<EM
|
|
>only</EM
|
|
> <I
|
|
CLASS="FIRSTTERM"
|
|
>whitespace</I
|
|
>
|
|
are <EM
|
|
>not</EM
|
|
> permitted.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>address[ ]="Blank" # Error!</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="NCTERM"
|
|
></A
|
|
>Enhancements to the
|
|
<A
|
|
HREF="testbranch.html#CASEESAC1"
|
|
>case</A
|
|
> construct:
|
|
the <TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>;;&</I
|
|
></TT
|
|
> and
|
|
<TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>;&</I
|
|
></TT
|
|
> terminators.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="CASE4"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-7. Testing characters</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
test_char ()
|
|
{
|
|
case "$1" in
|
|
[[:print:]] ) echo "$1 is a printable character.";;& # |
|
|
# The ;;& terminator continues to the next pattern test. |
|
|
[[:alnum:]] ) echo "$1 is an alpha/numeric character.";;& # v
|
|
[[:alpha:]] ) echo "$1 is an alphabetic character.";;& # v
|
|
[[:lower:]] ) echo "$1 is a lowercase alphabetic character.";;&
|
|
[[:digit:]] ) echo "$1 is an numeric character.";& # |
|
|
# The ;& terminator executes the next statement ... # |
|
|
%%%@@@@@ ) echo "********************************";; # v
|
|
# ^^^^^^^^ ... even with a dummy pattern.
|
|
esac
|
|
}
|
|
|
|
echo
|
|
|
|
test_char 3
|
|
# 3 is a printable character.
|
|
# 3 is an alpha/numeric character.
|
|
# 3 is an numeric character.
|
|
# ********************************
|
|
echo
|
|
|
|
test_char m
|
|
# m is a printable character.
|
|
# m is an alpha/numeric character.
|
|
# m is an alphabetic character.
|
|
# m is a lowercase alphabetic character.
|
|
echo
|
|
|
|
test_char /
|
|
# / is a printable character.
|
|
|
|
echo
|
|
|
|
# The ;;& terminator can save complex if/then conditions.
|
|
# The ;& is somewhat less useful.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="COPROCREF"
|
|
></A
|
|
>The new <B
|
|
CLASS="COMMAND"
|
|
>coproc</B
|
|
>
|
|
builtin enables two parallel <A
|
|
HREF="special-chars.html#PROCESSREF"
|
|
>processes</A
|
|
> to communicate and
|
|
interact. As Chet Ramey states in the
|
|
<A
|
|
HREF="biblio.html#BASHFAQ"
|
|
>Bash FAQ</A
|
|
>
|
|
<A
|
|
NAME="AEN21068"
|
|
HREF="#FTN.AEN21068"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[2]</SPAN
|
|
></A
|
|
>
|
|
, ver. 4.01:
|
|
</P
|
|
><A
|
|
NAME="AEN21070"
|
|
></A
|
|
><BLOCKQUOTE
|
|
CLASS="BLOCKQUOTE"
|
|
><P
|
|
CLASS="LITERALLAYOUT"
|
|
> There is a new 'coproc' reserved word that specifies a coprocess:<br>
|
|
an asynchronous command run with two pipes connected to the creating<br>
|
|
shell. Coprocs can be named. The input and output file descriptors<br>
|
|
and the PID of the coprocess are available to the calling shell in<br>
|
|
variables with coproc-specific names.<br>
|
|
<br>
|
|
George Dimitriu explains,<br>
|
|
"... coproc ... is a feature used in Bash process substitution,<br>
|
|
which now is made publicly available."<br>
|
|
This means it can be explicitly invoked in a script, rather than<br>
|
|
just being a behind-the-scenes mechanism used by Bash.<br>
|
|
</P
|
|
></BLOCKQUOTE
|
|
><P
|
|
>Coprocesses use <I
|
|
CLASS="FIRSTTERM"
|
|
>file descriptors</I
|
|
>.
|
|
<A
|
|
HREF="io-redirection.html#FDREF2"
|
|
>File descriptors enable processes and
|
|
pipes to communicate</A
|
|
>.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
# A coprocess communicates with a while-read loop.
|
|
|
|
|
|
coproc { cat mx_data.txt; sleep 2; }
|
|
# ^^^^^^^
|
|
# Try running this without "sleep 2" and see what happens.
|
|
|
|
while read -u ${COPROC[0]} line # ${COPROC[0]} is the
|
|
do #+ file descriptor of the coprocess.
|
|
echo "$line" | sed -e 's/line/NOT-ORIGINAL-TEXT/'
|
|
done
|
|
|
|
kill $COPROC_PID # No longer need the coprocess,
|
|
#+ so kill its PID.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
><P
|
|
>But, be careful!</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
echo; echo
|
|
a=aaa
|
|
b=bbb
|
|
c=ccc
|
|
|
|
coproc echo "one two three"
|
|
while read -u ${COPROC[0]} a b c; # Note that this loop
|
|
do #+ runs in a subshell.
|
|
echo "Inside while-read loop: ";
|
|
echo "a = $a"; echo "b = $b"; echo "c = $c"
|
|
echo "coproc file descriptor: ${COPROC[0]}"
|
|
done
|
|
|
|
# a = one
|
|
# b = two
|
|
# c = three
|
|
# So far, so good, but ...
|
|
|
|
echo "-----------------"
|
|
echo "Outside while-read loop: "
|
|
echo "a = $a" # a =
|
|
echo "b = $b" # b =
|
|
echo "c = $c" # c =
|
|
echo "coproc file descriptor: ${COPROC[0]}"
|
|
echo
|
|
# The coproc is still running, but ...
|
|
#+ it still doesn't enable the parent process
|
|
#+ to "inherit" variables from the child process, the while-read loop.
|
|
|
|
# Compare this to the "badread.sh" script.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
><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 coprocess is <I
|
|
CLASS="FIRSTTERM"
|
|
>asynchronous</I
|
|
>,
|
|
and this might cause a problem. It may terminate before another
|
|
process has finished communicating with it.</P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
coproc cpname { for i in {0..10}; do echo "index = $i"; done; }
|
|
# ^^^^^^ This is a *named* coprocess.
|
|
read -u ${cpname[0]}
|
|
echo $REPLY # index = 0
|
|
echo ${COPROC[0]} #+ No output ... the coprocess timed out
|
|
# after the first loop iteration.
|
|
|
|
|
|
|
|
# However, George Dimitriu has a partial fix.
|
|
|
|
coproc cpname { for i in {0..10}; do echo "index = $i"; done; sleep 1;
|
|
echo hi > myo; cat - >> myo; }
|
|
# ^^^^^ This is a *named* coprocess.
|
|
|
|
echo "I am main"$'\04' >&${cpname[1]}
|
|
myfd=${cpname[0]}
|
|
echo myfd=$myfd
|
|
|
|
### while read -u $myfd
|
|
### do
|
|
### echo $REPLY;
|
|
### done
|
|
|
|
echo $cpname_PID
|
|
|
|
# Run this with and without the commented-out while-loop, and it is
|
|
#+ apparent that each process, the executing shell and the coprocess,
|
|
#+ waits for the other to finish writing in its own write-enabled pipe.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="MAPFILEREF"
|
|
></A
|
|
>The new <B
|
|
CLASS="COMMAND"
|
|
>mapfile</B
|
|
>
|
|
builtin makes it possible to load an array with the contents
|
|
of a text file without using a loop or <A
|
|
HREF="arrays.html#ARRAYINITCS"
|
|
>command substitution</A
|
|
>.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
mapfile Arr1 < $0
|
|
# Same result as Arr1=( $(cat $0) )
|
|
echo "${Arr1[@]}" # Copies this entire script out to stdout.
|
|
|
|
echo "--"; echo
|
|
|
|
# But, not the same as read -a !!!
|
|
read -a Arr2 < $0
|
|
echo "${Arr2[@]}" # Reads only first line of script into the array.
|
|
|
|
exit</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The <A
|
|
HREF="internal.html#READREF"
|
|
>read</A
|
|
> builtin got
|
|
a minor facelift. The <TT
|
|
CLASS="OPTION"
|
|
>-t</TT
|
|
>
|
|
<A
|
|
HREF="internal.html#READTIMED"
|
|
>timeout</A
|
|
> option now accepts
|
|
(decimal) fractional values
|
|
<A
|
|
NAME="AEN21096"
|
|
HREF="#FTN.AEN21096"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[3]</SPAN
|
|
></A
|
|
>
|
|
and the <TT
|
|
CLASS="OPTION"
|
|
>-i</TT
|
|
> option
|
|
permits preloading the edit buffer.
|
|
<A
|
|
NAME="AEN21101"
|
|
HREF="#FTN.AEN21101"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[4]</SPAN
|
|
></A
|
|
>
|
|
Unfortunately, these enhancements are still a work in progress
|
|
and not (yet) usable in scripts.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="CASEMODPARAMSUB"
|
|
></A
|
|
>
|
|
<A
|
|
HREF="parameter-substitution.html#PARAMSUBREF"
|
|
>Parameter substitution</A
|
|
>
|
|
gets <I
|
|
CLASS="FIRSTTERM"
|
|
>case-modification</I
|
|
> operators.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
var=veryMixedUpVariable
|
|
echo ${var} # veryMixedUpVariable
|
|
echo ${var^} # VeryMixedUpVariable
|
|
# * First char --> uppercase.
|
|
echo ${var^^} # VERYMIXEDUPVARIABLE
|
|
# ** All chars --> uppercase.
|
|
echo ${var,} # veryMixedUpVariable
|
|
# * First char --> lowercase.
|
|
echo ${var,,} # verymixedupvariable
|
|
# ** All chars --> lowercase.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="DECLARECASEMOD"
|
|
></A
|
|
></P
|
|
><P
|
|
>The <A
|
|
HREF="declareref.html"
|
|
>declare</A
|
|
> builtin now
|
|
accepts the <TT
|
|
CLASS="OPTION"
|
|
>-l</TT
|
|
> <I
|
|
CLASS="FIRSTTERM"
|
|
>lowercase</I
|
|
>
|
|
and <TT
|
|
CLASS="OPTION"
|
|
>-c</TT
|
|
> <I
|
|
CLASS="FIRSTTERM"
|
|
>capitalize</I
|
|
>
|
|
options.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
declare -l var1 # Will change to lowercase
|
|
var1=MixedCaseVARIABLE
|
|
echo "$var1" # mixedcasevariable
|
|
# Same effect as echo $var1 | tr A-Z a-z
|
|
|
|
declare -c var2 # Changes only initial char to uppercase.
|
|
var2=originally_lowercase
|
|
echo "$var2" # Originally_lowercase
|
|
# NOT the same effect as echo $var2 | tr a-z A-Z</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="BRACEEXPREF4"
|
|
></A
|
|
>
|
|
<A
|
|
HREF="special-chars.html#BRACEEXPREF"
|
|
>Brace expansion</A
|
|
> has more options.</P
|
|
><P
|
|
><I
|
|
CLASS="FIRSTTERM"
|
|
>Increment/decrement</I
|
|
>, specified in the
|
|
final term within braces.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
echo {40..60..2}
|
|
# 40 42 44 46 48 50 52 54 56 58 60
|
|
# All the even numbers, between 40 and 60.
|
|
|
|
echo {60..40..2}
|
|
# 60 58 56 54 52 50 48 46 44 42 40
|
|
# All the even numbers, between 40 and 60, counting backwards.
|
|
# In effect, a decrement.
|
|
echo {60..40..-2}
|
|
# The same output. The minus sign is not necessary.
|
|
|
|
# But, what about letters and symbols?
|
|
echo {X..d}
|
|
# X Y Z [ ] ^ _ ` a b c d
|
|
# Does not echo the \ which escapes a space.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
><P
|
|
><I
|
|
CLASS="FIRSTTERM"
|
|
>Zero-padding</I
|
|
>, specified in the
|
|
first term within braces, prefixes each term in the output
|
|
with the <EM
|
|
>same number</EM
|
|
> of zeroes.</P
|
|
><TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash4$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>echo {010..15}</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>010 011 012 013 014 015</TT
|
|
>
|
|
|
|
|
|
<TT
|
|
CLASS="PROMPT"
|
|
>bash4$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>echo {000..10}</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>000 001 002 003 004 005 006 007 008 009 010</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="SUBSTREXTREF4"
|
|
></A
|
|
></P
|
|
><P
|
|
><A
|
|
HREF="bashver4.html#SUBSTREXTREF4"
|
|
><I
|
|
CLASS="FIRSTTERM"
|
|
>Substring
|
|
extraction</I
|
|
> on <I
|
|
CLASS="FIRSTTERM"
|
|
>positional
|
|
parameters</I
|
|
></A
|
|
> now starts with <A
|
|
HREF="othertypesv.html#SCRNAMEPARAM"
|
|
>$0</A
|
|
> as the
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>zero-index</I
|
|
>. (This corrects an
|
|
inconsistency in the treatment of positional parameters.)</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# show-params.bash
|
|
# Requires version 4+ of Bash.
|
|
|
|
# Invoke this scripts with at least one positional parameter.
|
|
|
|
E_BADPARAMS=99
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "Usage $0 param1 ..."
|
|
exit $E_BADPARAMS
|
|
fi
|
|
|
|
echo ${@:0}
|
|
|
|
# bash3 show-params.bash4 one two three
|
|
# one two three
|
|
|
|
# bash4 show-params.bash4 one two three
|
|
# show-params.bash4 one two three
|
|
|
|
# $0 $1 $2 $3</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="GLOBSTARREF"
|
|
></A
|
|
>The new <SPAN
|
|
CLASS="TOKEN"
|
|
>**</SPAN
|
|
>
|
|
<A
|
|
HREF="globbingref.html"
|
|
>globbing</A
|
|
> operator
|
|
matches filenames and directories
|
|
<A
|
|
HREF="localvar.html#RECURSIONREF0"
|
|
>recursively</A
|
|
>.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
# filelist.bash4
|
|
|
|
shopt -s globstar # Must enable globstar, otherwise ** doesn't work.
|
|
# The globstar shell option is new to version 4 of Bash.
|
|
|
|
echo "Using *"; echo
|
|
for filename in *
|
|
do
|
|
echo "$filename"
|
|
done # Lists only files in current directory ($PWD).
|
|
|
|
echo; echo "--------------"; echo
|
|
|
|
echo "Using **"
|
|
for filename in **
|
|
do
|
|
echo "$filename"
|
|
done # Lists complete file tree, recursively.
|
|
|
|
exit
|
|
|
|
Using *
|
|
|
|
allmyfiles
|
|
filelist.bash4
|
|
|
|
--------------
|
|
|
|
Using **
|
|
|
|
allmyfiles
|
|
allmyfiles/file.index.txt
|
|
allmyfiles/my_music
|
|
allmyfiles/my_music/me-singing-60s-folksongs.ogg
|
|
allmyfiles/my_music/me-singing-opera.ogg
|
|
allmyfiles/my_music/piano-lesson.1.ogg
|
|
allmyfiles/my_pictures
|
|
allmyfiles/my_pictures/at-beach-with-Jade.png
|
|
allmyfiles/my_pictures/picnic-with-Melissa.png
|
|
filelist.bash4</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The new <A
|
|
HREF="internalvariables.html#BASHPIDREF"
|
|
>$BASHPID</A
|
|
>
|
|
internal variable.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="CNFH"
|
|
></A
|
|
></P
|
|
><P
|
|
>There is a new <A
|
|
HREF="internal.html#BUILTINREF"
|
|
>builtin</A
|
|
>
|
|
error-handling function named
|
|
<B
|
|
CLASS="COMMAND"
|
|
>command_not_found_handle</B
|
|
>.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash4
|
|
|
|
command_not_found_handle ()
|
|
{ # Accepts implicit parameters.
|
|
echo "The following command is not valid: \""$1\"""
|
|
echo "With the following argument(s): \""$2\"" \""$3\""" # $4, $5 ...
|
|
} # $1, $2, etc. are not explicitly passed to the function.
|
|
|
|
bad_command arg1 arg2
|
|
|
|
# The following command is not valid: "bad_command"
|
|
# With the following argument(s): "arg1" "arg2"</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></P
|
|
></LI
|
|
></UL
|
|
><TABLE
|
|
CLASS="SIDEBAR"
|
|
BORDER="1"
|
|
CELLPADDING="5"
|
|
><TR
|
|
><TD
|
|
><DIV
|
|
CLASS="SIDEBAR"
|
|
><A
|
|
NAME="AEN21170"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
><EM
|
|
>Editorial comment</EM
|
|
></P
|
|
><P
|
|
>Associative arrays? Coprocesses? Whatever happened
|
|
to the lean and mean Bash we have come to know and love?
|
|
Could it be suffering from (horrors!) <SPAN
|
|
CLASS="QUOTE"
|
|
>"feature
|
|
creep"</SPAN
|
|
>? Or perhaps even Korn shell envy?</P
|
|
><P
|
|
><EM
|
|
>Note to Chet Ramey:</EM
|
|
> Please add only
|
|
<EM
|
|
>essential</EM
|
|
> features in future Bash
|
|
releases -- perhaps <I
|
|
CLASS="FIRSTTERM"
|
|
>for-each</I
|
|
>
|
|
loops and support for multi-dimensional arrays.
|
|
<A
|
|
NAME="AEN21179"
|
|
HREF="#FTN.AEN21179"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[5]</SPAN
|
|
></A
|
|
>
|
|
Most Bash users won't need, won't use, and likely won't greatly
|
|
appreciate complex <SPAN
|
|
CLASS="QUOTE"
|
|
>"features"</SPAN
|
|
> like built-in
|
|
debuggers, Perl interfaces, and bolt-on rocket boosters.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><DIV
|
|
CLASS="SECT2"
|
|
><H2
|
|
CLASS="SECT2"
|
|
><A
|
|
NAME="AEN21183"
|
|
></A
|
|
>37.3.1. Bash, version 4.1</H2
|
|
><P
|
|
><A
|
|
NAME="BASH41"
|
|
></A
|
|
>Version 4.1 of Bash, released in May,
|
|
2010, was primarily a bugfix update.</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>The <A
|
|
HREF="internal.html#PRINTFREF"
|
|
>printf</A
|
|
> command
|
|
now accepts a <TT
|
|
CLASS="OPTION"
|
|
>-v</TT
|
|
> option for setting <A
|
|
HREF="arrays.html#ARRAYREF"
|
|
>array</A
|
|
> indices.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Within <A
|
|
HREF="testconstructs.html#DBLBRACKETS"
|
|
>double brackets</A
|
|
>,
|
|
the <B
|
|
CLASS="COMMAND"
|
|
>></B
|
|
> and <B
|
|
CLASS="COMMAND"
|
|
><</B
|
|
>
|
|
string comparison operators now conform to the <A
|
|
HREF="localization.html#LOCALEREF"
|
|
>locale</A
|
|
>. Since the locale setting may
|
|
affect the sorting order of string expressions, this
|
|
has side-effects on comparison tests within
|
|
<EM
|
|
>[[ ... ]]</EM
|
|
> expressions.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>The <A
|
|
HREF="internal.html#READREF"
|
|
>read</A
|
|
> builtin
|
|
now takes a <TT
|
|
CLASS="OPTION"
|
|
>-N</TT
|
|
> option (<I
|
|
CLASS="FIRSTTERM"
|
|
>read -N
|
|
chars</I
|
|
>), which causes the <I
|
|
CLASS="FIRSTTERM"
|
|
>read</I
|
|
>
|
|
to terminate after <I
|
|
CLASS="FIRSTTERM"
|
|
>chars</I
|
|
>
|
|
characters.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="READN"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-8. Reading N characters</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# Requires Bash version -ge 4.1 ...
|
|
|
|
num_chars=61
|
|
|
|
read -N $num_chars var < $0 # Read first 61 characters of script!
|
|
echo "$var"
|
|
exit
|
|
|
|
####### Output of Script #######
|
|
|
|
#!/bin/bash
|
|
# Requires Bash version -ge 4.1 ...
|
|
|
|
num_chars=61</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="here-docs.html#HEREDOCREF"
|
|
>Here documents</A
|
|
>
|
|
embedded in <A
|
|
HREF="varassignment.html#COMMANDSUBREF0"
|
|
> <TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>$( ... )</B
|
|
></TT
|
|
> command substitution</A
|
|
>
|
|
constructs may terminate with a simple
|
|
<B
|
|
CLASS="COMMAND"
|
|
>)</B
|
|
>.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="HERECOMMSUB"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-9. Using a <I
|
|
CLASS="FIRSTTERM"
|
|
>here document</I
|
|
>
|
|
to set a variable</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# here-commsub.sh
|
|
# Requires Bash version -ge 4.1 ...
|
|
|
|
multi_line_var=$( cat <<ENDxxx
|
|
------------------------------
|
|
This is line 1 of the variable
|
|
This is line 2 of the variable
|
|
This is line 3 of the variable
|
|
------------------------------
|
|
ENDxxx)
|
|
|
|
# Rather than what Bash 4.0 requires:
|
|
#+ that the terminating limit string and
|
|
#+ the terminating close-parenthesis be on separate lines.
|
|
|
|
# ENDxxx
|
|
# )
|
|
|
|
|
|
echo "$multi_line_var"
|
|
|
|
# Bash still emits a warning, though.
|
|
# warning: here-document at line 10 delimited
|
|
#+ by end-of-file (wanted `ENDxxx')</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
></UL
|
|
></DIV
|
|
><DIV
|
|
CLASS="SECT2"
|
|
><H2
|
|
CLASS="SECT2"
|
|
><A
|
|
NAME="AEN21220"
|
|
></A
|
|
>37.3.2. Bash, version 4.2</H2
|
|
><P
|
|
><A
|
|
NAME="BASH42"
|
|
></A
|
|
>Version 4.2 of Bash, released
|
|
in February, 2011, contains a number of new features and
|
|
enhancements, in addition to bugfixes.</P
|
|
><P
|
|
></P
|
|
><UL
|
|
><LI
|
|
><P
|
|
>Bash now supports the the
|
|
<TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>\u</I
|
|
></TT
|
|
>
|
|
and <TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>\U</I
|
|
></TT
|
|
>
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>Unicode</I
|
|
> escape.</P
|
|
><P
|
|
><A
|
|
NAME="UNICODEREF"
|
|
></A
|
|
></P
|
|
><TABLE
|
|
CLASS="SIDEBAR"
|
|
BORDER="1"
|
|
CELLPADDING="5"
|
|
><TR
|
|
><TD
|
|
><DIV
|
|
CLASS="SIDEBAR"
|
|
><A
|
|
NAME="AEN21232"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
>Unicode is a cross-platform standard for encoding
|
|
into numerical values letters and graphic symbols.
|
|
This permits representing and displaying characters
|
|
in foreign alphabets and unusual fonts.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
><A
|
|
NAME="UNICODEREF2"
|
|
></A
|
|
></P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>echo -e '\u2630' # Horizontal triple bar character.
|
|
# Equivalent to the more roundabout:
|
|
echo -e "\xE2\x98\xB0"
|
|
# Recognized by earlier Bash versions.
|
|
|
|
echo -e '\u220F' # PI (Greek letter and mathematical symbol)
|
|
echo -e '\u0416' # Capital "ZHE" (Cyrillic letter)
|
|
echo -e '\u2708' # Airplane (Dingbat font) symbol
|
|
echo -e '\u2622' # Radioactivity trefoil
|
|
|
|
echo -e "The amplifier circuit requires a 100 \u2126 pull-up resistor."
|
|
|
|
|
|
unicode_var='\u2640'
|
|
echo -e $unicode_var # Female symbol
|
|
printf "$unicode_var \n" # Female symbol, with newline
|
|
|
|
|
|
# And for something a bit more elaborate . . .
|
|
|
|
# We can store Unicode symbols in an associative array,
|
|
#+ then retrieve them by name.
|
|
# Run this in a gnome-terminal or a terminal with a large, bold font
|
|
#+ for better legibility.
|
|
|
|
declare -A symbol # Associative array.
|
|
|
|
symbol[script_E]='\u2130'
|
|
symbol[script_F]='\u2131'
|
|
symbol[script_J]='\u2110'
|
|
symbol[script_M]='\u2133'
|
|
symbol[Rx]='\u211E'
|
|
symbol[TEL]='\u2121'
|
|
symbol[FAX]='\u213B'
|
|
symbol[care_of]='\u2105'
|
|
symbol[account]='\u2100'
|
|
symbol[trademark]='\u2122'
|
|
|
|
|
|
echo -ne "${symbol[script_E]} "
|
|
echo -ne "${symbol[script_F]} "
|
|
echo -ne "${symbol[script_J]} "
|
|
echo -ne "${symbol[script_M]} "
|
|
echo -ne "${symbol[Rx]} "
|
|
echo -ne "${symbol[TEL]} "
|
|
echo -ne "${symbol[FAX]} "
|
|
echo -ne "${symbol[care_of]} "
|
|
echo -ne "${symbol[account]} "
|
|
echo -ne "${symbol[trademark]} "
|
|
echo</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 above example uses the
|
|
<A
|
|
HREF="escapingsection.html#STRQ"
|
|
><B
|
|
CLASS="COMMAND"
|
|
>$' ... '</B
|
|
></A
|
|
>
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>string-expansion</I
|
|
> construct.</P
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
NAME="LASTPIPEREF"
|
|
></A
|
|
></P
|
|
><P
|
|
>When the <TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>lastpipe</I
|
|
></TT
|
|
> shell option
|
|
is set, the last command in a <A
|
|
HREF="special-chars.html#PIPEREF"
|
|
>pipe</A
|
|
> <EM
|
|
>doesn't run in a
|
|
subshell</EM
|
|
>.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="LASTPIPEOPT"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-10. Piping input to a <A
|
|
HREF="internal.html#READREF"
|
|
>read</A
|
|
></B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# lastpipe-option.sh
|
|
|
|
line='' # Null value.
|
|
echo "\$line = "$line"" # $line =
|
|
|
|
echo
|
|
|
|
shopt -s lastpipe # Error on Bash version -lt 4.2.
|
|
echo "Exit status of attempting to set \"lastpipe\" option is $?"
|
|
# 1 if Bash version -lt 4.2, 0 otherwise.
|
|
|
|
echo
|
|
|
|
head -1 $0 | read line # Pipe the first line of the script to read.
|
|
# ^^^^^^^^^ Not in a subshell!!!
|
|
|
|
echo "\$line = "$line""
|
|
# Older Bash releases $line =
|
|
# Bash version 4.2 $line = #!/bin/bash</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>This option offers possible <SPAN
|
|
CLASS="QUOTE"
|
|
>"fixups"</SPAN
|
|
>
|
|
for these example scripts:
|
|
<A
|
|
HREF="gotchas.html#BADREAD"
|
|
>Example 34-3</A
|
|
> and
|
|
<A
|
|
HREF="internal.html#READPIPE"
|
|
>Example 15-8</A
|
|
>.</P
|
|
></LI
|
|
><LI
|
|
><P
|
|
>Negative <A
|
|
HREF="arrays.html#ARRAYREF"
|
|
>array</A
|
|
> indices
|
|
permit counting backwards from the end of an array.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="NEGARRAY"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-11. Negative array indices</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# neg-array.sh
|
|
# Requires Bash, version -ge 4.2.
|
|
|
|
array=( zero one two three four five ) # Six-element array.
|
|
# 0 1 2 3 4 5
|
|
# -6 -5 -4 -3 -2 -1
|
|
|
|
# Negative array indices now permitted.
|
|
echo ${array[-1]} # five
|
|
echo ${array[-2]} # four
|
|
# ...
|
|
echo ${array[-6]} # zero
|
|
# Negative array indices count backward from the last element+1.
|
|
|
|
# But, you cannot index past the beginning of the array.
|
|
echo ${array[-7]} # array: bad array subscript
|
|
|
|
|
|
# So, what is this new feature good for?
|
|
|
|
echo "The last element in the array is "${array[-1]}""
|
|
# Which is quite a bit more straightforward than:
|
|
echo "The last element in the array is "${array[${#array[*]}-1]}""
|
|
echo
|
|
|
|
# And ...
|
|
|
|
index=0
|
|
let "neg_element_count = 0 - ${#array[*]}"
|
|
# Number of elements, converted to a negative number.
|
|
|
|
while [ $index -gt $neg_element_count ]; do
|
|
((index--)); echo -n "${array[index]} "
|
|
done # Lists the elements in the array, backwards.
|
|
# We have just simulated the "tac" command on this array.
|
|
|
|
echo
|
|
|
|
# See also neg-offset.sh.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
><LI
|
|
><P
|
|
><A
|
|
HREF="string-manipulation.html#SUBSTREXTR01"
|
|
>Substring extraction</A
|
|
>
|
|
uses a negative <I
|
|
CLASS="FIRSTTERM"
|
|
>length</I
|
|
> parameter to
|
|
specify an offset from the <I
|
|
CLASS="FIRSTTERM"
|
|
>end</I
|
|
> of the
|
|
target string.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="NEGOFFSET"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-12. Negative parameter in string-extraction
|
|
construct</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="90%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# Bash, version -ge 4.2
|
|
# Negative length-index in substring extraction.
|
|
# Important: It changes the interpretation of this construct!
|
|
|
|
stringZ=abcABC123ABCabc
|
|
|
|
echo ${stringZ} # abcABC123ABCabc
|
|
# Position within string: 0123456789.....
|
|
echo ${stringZ:2:3} # cAB
|
|
# Count 2 chars forward from string beginning, and extract 3 chars.
|
|
# ${string:position:length}
|
|
|
|
# So far, nothing new, but now ...
|
|
|
|
# abcABC123ABCabc
|
|
# Position within string: 0123....6543210
|
|
echo ${stringZ:3:-6} # ABC123
|
|
# ^
|
|
# Index 3 chars forward from beginning and 6 chars backward from end,
|
|
#+ and extract everything in between.
|
|
# ${string:offset-from-front:offset-from-end}
|
|
# When the "length" parameter is negative,
|
|
#+ it serves as an offset-from-end parameter.
|
|
|
|
# See also neg-array.sh.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></LI
|
|
></UL
|
|
></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.AEN21025"
|
|
HREF="bashver4.html#AEN21025"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[1]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>To be more specific, Bash 4+ has
|
|
<EM
|
|
>limited</EM
|
|
> support for associative
|
|
arrays. It's a bare-bones implementation,
|
|
and it lacks the much of the functionality of such
|
|
arrays in other programming languages. Note, however,
|
|
that <A
|
|
HREF="optimizations.html#ASSOCARRTST"
|
|
>associative arrays in
|
|
Bash seem to execute faster and more efficiently than
|
|
numerically-indexed arrays</A
|
|
>.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN21068"
|
|
HREF="bashver4.html#AEN21068"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[2]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>Copyright 1995-2009 by Chester Ramey.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN21096"
|
|
HREF="bashver4.html#AEN21096"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[3]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>This only works with <A
|
|
HREF="special-chars.html#PIPEREF"
|
|
>pipes</A
|
|
> and certain other
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>special</I
|
|
> files.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN21101"
|
|
HREF="bashver4.html#AEN21101"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[4]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>But only in conjunction with
|
|
<A
|
|
HREF="internal.html#READLINEREF"
|
|
>readline</A
|
|
>, i.e.,
|
|
from the command-line.</P
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="5%"
|
|
><A
|
|
NAME="FTN.AEN21179"
|
|
HREF="bashver4.html#AEN21179"
|
|
><SPAN
|
|
CLASS="footnote"
|
|
>[5]</SPAN
|
|
></A
|
|
></TD
|
|
><TD
|
|
ALIGN="LEFT"
|
|
VALIGN="TOP"
|
|
WIDTH="95%"
|
|
><P
|
|
>And while you're at it, consider fixing
|
|
the notorious <A
|
|
HREF="internal.html#PIPEREADREF0"
|
|
>piped read</A
|
|
>
|
|
problem.</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="bashver3.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="endnotes.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Bash, version 3</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="bash2.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Endnotes</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |