代码块,例如 while、until 和 for 循环,甚至 if/then 测试块也可以包含重定向stdin。甚至函数也可以使用这种形式的重定向(参见示例 24-11)。代码块末尾的 < 运算符可以实现这一点。
示例 20-5。重定向的 while 循环
| #!/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. | 
示例 20-6。重定向的 while 循环的替代形式
| #!/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 | 
示例 20-7。重定向的 until 循环
| #!/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 | 
示例 20-8。重定向的 for 循环
| #!/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 | 
我们可以修改前面的示例,同时重定向循环的输出。
示例 20-9。重定向的 for 循环(同时stdin和stdout已重定向)
| #!/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 | 
示例 20-10。重定向的 if/then 测试
| #!/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 | 
示例 20-11。用于上述示例的数据文件 names.data
| 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". | 
重定向stdout代码块的效果是将输出保存到文件中。参见 示例 3-2。
Here documents 是重定向代码块的一个特例。既然如此,应该可以将 here document 的输出馈送到stdin用于 while loop。
| # 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" |