x13380.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><HTML><HEAD><TITLE>使用exec</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINKREL="HOME"TITLE="高级Bash脚本编程指南"HREF="index.html"><LINKREL="UP"TITLE="I/O重定向"HREF="io-redirection.html"><LINKREL="PREVIOUS"TITLE="I/O重定向"HREF="io-redirection.html"><LINKREL="NEXT"TITLE="代码块重定向"HREF="redircb.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="io-redirection.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">16. I/O重定向</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="redircb.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="AEN13380">16.1. 使用<BCLASS="COMMAND">exec</B></A></H1><P><ANAME="USINGEXECREF"></A></P><P><BCLASS="COMMAND">exec <filename</B>命令会将<TTCLASS="FILENAME">stdin</TT>重定向到文件中. 从这句开始, 所有的<TTCLASS="FILENAME">stdin</TT>就都来自于这个文件了, 而不是标准输入(通常都是键盘输入). 这样就提供了一种按行读取文件的方法, 并且可以使用<AHREF="sedawk.html#SEDREF">sed</A>和/或<AHREF="awk.html#AWKREF">awk</A>来对每一行进行分析. </P><DIVCLASS="EXAMPLE"><HR><ANAME="REDIR1"></A><P><B>例子 16-1. 使用<BCLASS="COMMAND">exec</B>重定向<TTCLASS="FILENAME">stdin</TT></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 使用'exec'重定向stdin. 3 4 5 exec 6<&0 # 将文件描述符#6与stdin链接起来. 6 # 保存stdin. 7 8 exec < data-file # stdin被文件"data-file"所代替. 9 10 read a1 # 读取文件"data-file"的第一行. 11 read a2 # 读取文件"data-file"的第二行. 12 13 echo 14 echo "Following lines read from file." 15 echo "-------------------------------" 16 echo $a1 17 echo $a2 18 19 echo; echo; echo 20 21 exec 0<&6 6<&- 22 # 现在将stdin从fd #6中恢复, 因为刚才我们把stdin重定向到#6了, 23 #+ 然后关闭fd #6 ( 6<&- ), 好让这个描述符继续被其他进程所使用. 24 # 25 # <&6 6<&- 这么做也可以. 26 27 echo -n "Enter data " 28 read b1 # 现在"read"已经恢复正常了, 就是能够正常的从stdin中读取. 29 echo "Input read from stdin." 30 echo "----------------------" 31 echo "b1 = $b1" 32 33 echo 34 35 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>同样的, <BCLASS="COMMAND">exec >filename</B>命令将会把<TTCLASS="FILENAME">stdout</TT>重定向到一个指定的文件中. 这样所有命令的输出就都会发送到那个指定的文件, 而不是<TTCLASS="FILENAME">stdout</TT>. </P><DIVCLASS="IMPORTANT"><P></P><TABLECLASS="IMPORTANT"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/important.gif"HSPACE="5"ALT="Important"></TD><TDALIGN="LEFT"VALIGN="TOP"><P> <BCLASS="COMMAND">exec N > filename</B>会影响整个脚本或<EM>当前shell</EM>. 对于这个指定<AHREF="special-chars.html#PROCESSIDREF">PID</A>的脚本或shell来说, 从这句命令执行之后, 就会重定向到这个文件中, 然而 . . . </P><P> <BCLASS="COMMAND">N > filename</B>只会影响新fork出来的进程, 而不会影响整个脚本或shell. not the entire script or shell. </P><P>感谢你, Ahmed Darwish, 指出这个问题. </P></TD></TR></TABLE></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="REASSIGNSTDOUT"></A><P><B>例子 16-2. 使用<BCLASS="COMMAND">exec</B>来重定向<TTCLASS="FILENAME">stdout</TT></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # reassign-stdout.sh 3 4 LOGFILE=logfile.txt 5 6 exec 6>&1 # 将fd #6与stdout链接起来. 7 # 保存stdout. 8 9 exec > $LOGFILE # stdout就被文件"logfile.txt"所代替了. 10 11 # ----------------------------------------------------------- # 12 # 在这块中所有命令的输出都会发送到文件$LOGFILE中. 13 14 echo -n "Logfile: " 15 date 16 echo "-------------------------------------" 17 echo 18 19 echo "Output of \"ls -al\" command" 20 echo 21 ls -al 22 echo; echo 23 echo "Output of \"df\" command" 24 echo 25 df 26 27 # ----------------------------------------------------------- # 28 29 exec 1>&6 6>&- # 恢复stdout, 然后关闭文件描述符#6. 30 31 echo 32 echo "== stdout now restored to default == " 33 echo 34 ls -al 35 echo 36 37 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="UPPERCONV"></A><P><B>例子 16-3. 使用<BCLASS="COMMAND">exec</B>在同一个脚本中重定向<TTCLASS="FILENAME">stdin</TT>和<TTCLASS="FILENAME">stdout</TT></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # upperconv.sh 3 # 将一个指定的输入文件转换为大写. 4 5 E_FILE_ACCESS=70 6 E_WRONG_ARGS=71 7 8 if [ ! -r "$1" ] # 判断指定的输入文件是否可读? 9 then 10 echo "Can't read from input file!" 11 echo "Usage: $0 input-file output-file" 12 exit $E_FILE_ACCESS 13 fi # 即使输入文件($1)没被指定 14 #+ 也还是会以相同的错误退出(为什么?). 15 16 if [ -z "$2" ] 17 then 18 echo "Need to specify output file." 19 echo "Usage: $0 input-file output-file" 20 exit $E_WRONG_ARGS 21 fi 22 23 24 exec 4<&0 25 exec < $1 # 将会从输入文件中读取. 26 27 exec 7>&1 28 exec > $2 # 将写到输出文件中. 29 # 假设输出文件是可写的(添加检查?). 30 31 # ----------------------------------------------- 32 cat - | tr a-z A-Z # 转换为大写. 33 # ^^^^^ # 从stdin中读取. 34 # ^^^^^^^^^^ # 写到stdout上. 35 # 然而, stdin和stdout都被重定向了. 36 # ----------------------------------------------- 37 38 exec 1>&7 7>&- # 恢复stout. 39 exec 0<&4 4<&- # 恢复stdin. 40 41 # 恢复之后, 下边这行代码将会如预期的一样打印到stdout上. 42 echo "File \"$1\" written to \"$2\" as uppercase conversion." 43 44 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>I/O重定向是一种避免可怕的<AHREF="subshells.html#PARVIS">子shell中不可访问变量</A>问题的方法. </P><DIVCLASS="EXAMPLE"><HR><ANAME="AVOIDSUBSHELL"></A><P><B>例子 16-4. 避免子shell</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # avoid-subshell.sh 3 # 由Matthew Walker所提出的建议. 4 5 Lines=0 6 7 echo 8 9 cat myfile.txt | while read line; # (译者注: 管道会产生子shell) 10 do { 11 echo $line 12 (( Lines++ )); # 增加这个变量的值 13 #+ 但是外部循环却不能访问. 14 # 子shell问题. 15 } 16 done 17 18 echo "Number of lines read = $Lines" # 0 19 # 错误! 20 21 echo "------------------------" 22 23 24 exec 3<> myfile.txt 25 while read line <&3 26 do { 27 echo "$line" 28 (( Lines++ )); # 增加这个变量的值 29 #+ 现在外部循环就可以访问了. 30 # 没有子shell, 现在就没问题了. 31 } 32 done 33 exec 3>&- 34 35 echo "Number of lines read = $Lines" # 8 36 37 echo 38 39 exit 0 40 41 # 下边这些行是这个脚本的结果, 脚本是不会走到这里的. 42 43 $ cat myfile.txt 44 45 Line 1. 46 Line 2. 47 Line 3. 48 Line 4. 49 Line 5. 50 Line 6. 51 Line 7. 52 Line 8.</PRE></FONT></TD></TR></TABLE><HR></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="io-redirection.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="redircb.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">I/O重定向</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="io-redirection.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">代码块重定向</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -