666 lines
11 KiB
HTML
666 lines
11 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Redirecting Code Blocks</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="I/O Redirection"
|
|
HREF="io-redirection.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Using exec"
|
|
HREF="x17974.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Applications"
|
|
HREF="redirapps.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="x17974.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Chapter 20. I/O Redirection</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="redirapps.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECT1"
|
|
><H1
|
|
CLASS="SECT1"
|
|
><A
|
|
NAME="REDIRCB"
|
|
></A
|
|
>20.2. Redirecting Code Blocks</H1
|
|
><P
|
|
><A
|
|
NAME="REDIRREF"
|
|
></A
|
|
>Blocks of code, such as <A
|
|
HREF="loops1.html#WHILELOOPREF"
|
|
>while</A
|
|
>, <A
|
|
HREF="loops1.html#UNTILLOOPREF"
|
|
>until</A
|
|
>, and <A
|
|
HREF="loops1.html#FORLOOPREF1"
|
|
>for</A
|
|
> loops, even <A
|
|
HREF="tests.html#IFTHEN"
|
|
>if/then</A
|
|
> test blocks can also incorporate
|
|
redirection of <TT
|
|
CLASS="FILENAME"
|
|
>stdin</TT
|
|
>. Even a function may
|
|
use this form of redirection (see <A
|
|
HREF="complexfunct.html#REALNAME"
|
|
>Example 24-11</A
|
|
>).
|
|
The <SPAN
|
|
CLASS="TOKEN"
|
|
><</SPAN
|
|
> operator at the end of the code block
|
|
accomplishes this.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR2"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-5. Redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>while</I
|
|
> loop</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# redir2.sh
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
#+ Filename=${1:-names.data}
|
|
# can replace the above test (parameter substitution).
|
|
|
|
count=0
|
|
|
|
echo
|
|
|
|
while [ "$name" != Smith ] # Why is variable $name in quotes?
|
|
do
|
|
read name # Reads from $Filename, rather than stdin.
|
|
echo $name
|
|
let "count += 1"
|
|
done <"$Filename" # Redirects stdin to file $Filename.
|
|
# ^^^^^^^^^^^^
|
|
|
|
echo; echo "$count names read"; echo
|
|
|
|
exit 0
|
|
|
|
# Note that in some older shell scripting languages,
|
|
#+ the redirected loop would run as a subshell.
|
|
# Therefore, $count would return 0, the initialized value outside the loop.
|
|
# Bash and ksh avoid starting a subshell *whenever possible*,
|
|
#+ so that this script, for example, runs correctly.
|
|
# (Thanks to Heiner Steven for pointing this out.)
|
|
|
|
# However . . .
|
|
# Bash *can* sometimes start a subshell in a PIPED "while-read" loop,
|
|
#+ as distinct from a REDIRECTED "while" loop.
|
|
|
|
abc=hi
|
|
echo -e "1\n2\n3" | while read l
|
|
do abc="$l"
|
|
echo $abc
|
|
done
|
|
echo $abc
|
|
|
|
# Thanks, Bruno de Oliveira Schneider, for demonstrating this
|
|
#+ with the above snippet of code.
|
|
# And, thanks, Brian Onn, for correcting an annotation error.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR2A"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-6. Alternate form of redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>while</I
|
|
> loop</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
# This is an alternate form of the preceding script.
|
|
|
|
# Suggested by Heiner Steven
|
|
#+ as a workaround in those situations when a redirect loop
|
|
#+ runs as a subshell, and therefore variables inside the loop
|
|
# +do not keep their values upon loop termination.
|
|
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
|
|
|
|
exec 3<&0 # Save stdin to file descriptor 3.
|
|
exec 0<"$Filename" # Redirect standard input.
|
|
|
|
count=0
|
|
echo
|
|
|
|
|
|
while [ "$name" != Smith ]
|
|
do
|
|
read name # Reads from redirected stdin ($Filename).
|
|
echo $name
|
|
let "count += 1"
|
|
done # Loop reads from file $Filename
|
|
#+ because of line 20.
|
|
|
|
# The original version of this script terminated the "while" loop with
|
|
#+ done <"$Filename"
|
|
# Exercise:
|
|
# Why is this unnecessary?
|
|
|
|
|
|
exec 0<&3 # Restore old stdin.
|
|
exec 3<&- # Close temporary fd 3.
|
|
|
|
echo; echo "$count names read"; echo
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR3"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-7. Redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>until</I
|
|
> loop</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# Same as previous example, but with "until" loop.
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
|
|
# while [ "$name" != Smith ]
|
|
until [ "$name" = Smith ] # Change != to =.
|
|
do
|
|
read name # Reads from $Filename, rather than stdin.
|
|
echo $name
|
|
done <"$Filename" # Redirects stdin to file $Filename.
|
|
# ^^^^^^^^^^^^
|
|
|
|
# Same results as with "while" loop in previous example.
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR4"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-8. Redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>for</I
|
|
> loop</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
|
|
line_count=`wc $Filename | awk '{ print $1 }'`
|
|
# Number of lines in target file.
|
|
#
|
|
# Very contrived and kludgy, nevertheless shows that
|
|
#+ it's possible to redirect stdin within a "for" loop...
|
|
#+ if you're clever enough.
|
|
#
|
|
# More concise is line_count=$(wc -l < "$Filename")
|
|
|
|
|
|
for name in `seq $line_count` # Recall that "seq" prints sequence of numbers.
|
|
# while [ "$name" != Smith ] -- more complicated than a "while" loop --
|
|
do
|
|
read name # Reads from $Filename, rather than stdin.
|
|
echo $name
|
|
if [ "$name" = Smith ] # Need all this extra baggage here.
|
|
then
|
|
break
|
|
fi
|
|
done <"$Filename" # Redirects stdin to file $Filename.
|
|
# ^^^^^^^^^^^^
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>We can modify the previous example to also redirect the output of
|
|
the loop.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR4A"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-9. Redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>for</I
|
|
> loop (both
|
|
<TT
|
|
CLASS="FILENAME"
|
|
>stdin</TT
|
|
> and <TT
|
|
CLASS="FILENAME"
|
|
>stdout</TT
|
|
>
|
|
redirected)</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
|
|
Savefile=$Filename.new # Filename to save results in.
|
|
FinalName=Jonah # Name to terminate "read" on.
|
|
|
|
line_count=`wc $Filename | awk '{ print $1 }'` # Number of lines in target file.
|
|
|
|
|
|
for name in `seq $line_count`
|
|
do
|
|
read name
|
|
echo "$name"
|
|
if [ "$name" = "$FinalName" ]
|
|
then
|
|
break
|
|
fi
|
|
done < "$Filename" > "$Savefile" # Redirects stdin to file $Filename,
|
|
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ and saves it to backup file.
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="REDIR5"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-10. Redirected <I
|
|
CLASS="FIRSTTERM"
|
|
>if/then</I
|
|
> test</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
Filename=names.data # Default, if no filename specified.
|
|
else
|
|
Filename=$1
|
|
fi
|
|
|
|
TRUE=1
|
|
|
|
if [ "$TRUE" ] # if true and if : also work.
|
|
then
|
|
read name
|
|
echo $name
|
|
fi <"$Filename"
|
|
# ^^^^^^^^^^^^
|
|
|
|
# Reads only first line of file.
|
|
# An "if/then" test has no way of iterating unless embedded in a loop.
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="NAMESDATA"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 20-11. Data file <I
|
|
CLASS="FIRSTTERM"
|
|
>names.data</I
|
|
> for above
|
|
examples</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>Aristotle
|
|
Arrhenius
|
|
Belisarius
|
|
Capablanca
|
|
Dickens
|
|
Euler
|
|
Goethe
|
|
Hegel
|
|
Jonah
|
|
Laplace
|
|
Maroczy
|
|
Purcell
|
|
Schmidt
|
|
Schopenhauer
|
|
Semmelweiss
|
|
Smith
|
|
Steinmetz
|
|
Tukhashevsky
|
|
Turing
|
|
Venn
|
|
Warshawski
|
|
Znosko-Borowski
|
|
|
|
# This is a data file for
|
|
#+ "redir2.sh", "redir3.sh", "redir4.sh", "redir4a.sh", "redir5.sh".</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
>Redirecting the <TT
|
|
CLASS="FILENAME"
|
|
>stdout</TT
|
|
> of a code
|
|
block has the effect of saving its output to a file. See <A
|
|
HREF="special-chars.html#RPMCHECK"
|
|
>Example 3-2</A
|
|
>.</P
|
|
><P
|
|
><A
|
|
HREF="here-docs.html#HEREDOCREF"
|
|
>Here documents</A
|
|
>
|
|
are a special case of redirected code blocks. That being the case,
|
|
it should be possible to feed the output of a <I
|
|
CLASS="FIRSTTERM"
|
|
>here
|
|
document</I
|
|
> into the <TT
|
|
CLASS="FILENAME"
|
|
>stdin</TT
|
|
> for a
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>while loop</I
|
|
>.</P
|
|
><P
|
|
> <TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
># This example by Albert Siersema
|
|
# Used with permission (thanks!).
|
|
|
|
function doesOutput()
|
|
# Could be an external command too, of course.
|
|
# Here we show you can use a function as well.
|
|
{
|
|
ls -al *.jpg | awk '{print $5,$9}'
|
|
}
|
|
|
|
|
|
nr=0 # We want the while loop to be able to manipulate these and
|
|
totalSize=0 #+ to be able to see the changes after the 'while' finished.
|
|
|
|
while read fileSize fileName ; do
|
|
echo "$fileName is $fileSize bytes"
|
|
let nr++
|
|
totalSize=$((totalSize+fileSize)) # Or: "let totalSize+=fileSize"
|
|
done<<EOF
|
|
$(doesOutput)
|
|
EOF
|
|
|
|
echo "$nr files totaling $totalSize bytes"</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
></DIV
|
|
><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="x17974.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="redirapps.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Using <I
|
|
CLASS="FIRSTTERM"
|
|
>exec</I
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="io-redirection.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Applications</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |