shell教程
OutOfMemory.CN技术专栏-> shell-> shell教程-> 16.2. 代码块重定向

16.2. 代码块重定向

像while,until,和for循环代码块,甚至if/then测试结构的代码块都能做到标准输入的重定向.即使函数也可以使用这种重定向的格式(参考例子23-11).所有的这些依

while, until, 和 for 循环代码块, 甚至 if/then 测试结构的代码块都能做到标准输入的重定向. 即使函数也可以使用这种重定向的格式 (参考例子 23-11). 所有的这些依靠代码块结尾的 < 操作符来做到.


例子 16-5. while 循环的重定向

#!/bin/bash
# redir2.sh

if [ -z "$1" ]
then
  Filename=names.data       # 如果没有指定文件名,则指定这个默认值.
else
  Filename=$1
fi
#+ Filename=${1:-names.data}
#  这句可代替上面的测试 (参数替换).

count=0

echo

while [ "$name" != Smith ]  # 为什么变量 $name 要用引号?
do
  read name                 # 从$Filename文件中读而非在标准输入中读.
  echo $name
  let "count += 1"
done <"$Filename"           # 重定向标准输入到文件$Filename.
#    ^^^^^^^^^^^^

echo; echo "$count names read"; echo

exit 0

#  注意在老一些的shell脚本编程语言里,
#+ 重定向的循环是在子shell里运行的.
#  因此, $count 值返回后会是 0, 此值是在循环开始前的值.
#  Bash 和 ksh 只要可能就避免启用子shell,
#+ 因此这个例子能正确运行.
#  (多谢Heiner Steven指出这个问题.)

# 然而 . . .
# Bash有时仍会启用一个子shell来处理重定向的"while"循环.

abc=hi
echo -e "1\n2\n3" | while read l
     do abc="$l"
        echo $abc
     done
echo $abc

# (多谢Bruno de Oliveira Schneider给出上面的代码片段来演示此问题.)
#


例子 16-6. 重定向while 循环的另一种形式

#!/bin/bash

# 这是前个脚本的另一个版本.

#  Heiner Steven谈到
#+ 在重定向循环时会以子Shell运行的环境里,
#+ 循环内的值在循环结束后不会保持循环内的值.
#


if [ -z "$1" ]
then
  Filename=names.data     # 如果没有指定文件名则使用默认值.
else
  Filename=$1
fi


exec 3<&0                 # 把标准输入关联到文件描述符.
exec 0<"$Filename"        # 重定向标准输入.

count=0
echo


while [ "$name" != Smith ]
do
  read name               # 从标准输入($Filename)中读.
  echo $name
  let "count += 1"
done                      #  从文件$Filename中循环的读
                          #+ 因为文件(译者注:指默认的文件,在这节最后面附上)有20行.

#  这个脚本原先在"while"循环的结尾是用:
#+      done <"$Filename"
#  练习:
#  为什么这是不必要的?


exec 0<&3                 # 恢复旧的标准输入.
exec 3<&-                 # 关闭临时文件描述符3.

echo; echo "$count names read"; echo

exit 0


例子 16-7. 重定向 until 循环

#!/bin/bash
# 和前面的例子相同, 但使用的是"until"循环.

if [ -z "$1" ]
then
  Filename=names.data         # 如果没有指定文件名使用默认值.
else
  Filename=$1
fi

# while [ "$name" != Smith ]
until [ "$name" = Smith ]     # 把 !=  改为 =.
do
  read name                   # 从文件$Filename中读而非从标准输入中读.
  echo $name
done <"$Filename"             # 重定向标准输入到文件$Filename.
#    ^^^^^^^^^^^^

# 结果和前面的"while"循环例子相同.

exit 0


例子 16-8. 重定向 for 循环

#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data          # 如果没有指定文件名就使用默认值.
else
  Filename=$1
fi

line_count=`wc $Filename | awk '{ print $1 }'`
#           目标文件的行数.
#
#  代码非常的刻意和难看,但至少展示了for循环的标准输入可以重定向...
#+ 当然你要足够聪明能看出来.
#
#
# 更简洁的办法是     line_count=$(wc -l < "$Filename")


for name in `seq $line_count`  # 调用 "seq" 来打印数字序列.
# while [ "$name" != Smith ]   --   for循环比单个"while"循环更复杂   --
do
  read name                    # 从$Filename文件而非标准输入读.
  echo $name
  if [ "$name" = Smith ]       # 因为用for循环,所以需要这个累赘测试.
  then
    break
  fi
done <"$Filename"              # 重定向标准输入到文件 $Filename.
#    ^^^^^^^^^^^^

exit 0

我们也可以修改前面的例子使其能重定向循环的标准输出.


例子 16-9. 重定向 for 循环 (标准输入和标准输出都做重定向)

#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data          # 如果没有指定文件名,则使用默认值.
else
  Filename=$1
fi

Savefile=$Filename.new         # 保存结果的文件名.
FinalName=Jonah                # 终止"read"时的名称.

line_count=`wc $Filename | awk '{ print $1 }'`  # 目标文件的行数.


for name in `seq $line_count`
do
  read name
  echo "$name"
  if [ "$name" = "$FinalName" ]
  then
    break
  fi
done < "$Filename" > "$Savefile"     # 重定向标准输出到文件 $Filename,
#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^       并保存输出到备份文件中.

exit 0


例子 16-10. 重定向 if/then 测试结构

#!/bin/bash

if [ -z "$1" ]
then
  Filename=names.data   # 如果文件名没有指定,使用默认值.
else
  Filename=$1
fi

TRUE=1

if [ "$TRUE" ]          # if true    和   if :   都可以.
then
 read name
 echo $name
fi <"$Filename"
#  ^^^^^^^^^^^^

# 只读了文件的第一行.
# "if/then"测试结构不会自动地反复地执行,除非把它们嵌到循环里.

exit 0


例子 16-11. 用于上面例子的"names.data"数据文件

Aristotle
Belisarius
Capablanca
Euler
Goethe
Hamurabi
Jonah
Laplace
Maroczy
Purcell
Schmidt
Semmelweiss
Smith
Turing
Venn
Wilson
Znosko-Borowski

#  此数据文件用于:
#+ "redir2.sh", "redir3.sh", "redir4.sh", "redir4a.sh", "redir5.sh".

重定向代码块的标准输出有保存它的输出到文件中的作用. 参考例子 3-2.

Here documents 是重定向代码块的一个特例.

© 内存溢出 OutOfMemory.CN