Bash脚本进阶指南
Repo
  • 正文
    • 第一部分 初见shell
      • 1. 为什么使用shell编程
      • 2. 和Sha-Bang(#!)一起出发
        • 2.1 调用一个脚本
        • 2.2 牛刀小试
    • 第二部分 shell基础
      • 3. 特殊字符
      • 4. 变量与参数
        • 4.1 变量替换
        • 4.2 变量赋值
        • 4.3 Bash弱类型变量
        • 4.4 特殊变量类型
      • 5. 引用
        • 5.1 引用变量
        • 5.2 转义
      • 6. 退出与退出状态
      • 7. 测试
        • 7.1 测试结构
        • 7.2 文件测试操作
        • 7.3 其他比较操作
        • 7.4 嵌套 if/then 条件测试
        • 7.5 牛刀小试
      • 8. 运算符相关话题
        • 8.1 运算符
        • 8.2 数字常量
        • 8.3 双圆括号结构
        • 8.4 运算符优先级
    • 第三部分 shell进阶
      • 9. 换个角度看变量
        • 9.1 内部变量
        • 9.2 变量类型标注:declare 与 typeset
          • 9.2.1 declare 的另类用法
        • 9.3 $RANDOM:生成随机数
      • 10. 变量处理
        • 10.1 字符串处理
          • 10.1.1 使用 awk 处理字符串
          • 10.1.2 参考资料
        • 10.2 参数替换
      • 11. 循环与分支
        • 11.1 循环
        • 11.2 嵌套循环
        • 11.3 循环控制
        • 11.4 测试与分支
      • 12. 命令替换
      • 13. 算术扩展
      • 14. 休息时间
    • 第四部分 命令
      • 15. 内建命令
        • 15.1 任务控制命令
      • 16. 外部筛选器,任务及命令
        • 16.1 基础命令
        • 16.2 复杂命令
        • 16.3 时间/日期命令
        • 16.4 文本处理命令
        • 16.5 文件与归档命令
        • 16.6 通信命令
        • 16.7 终端控制命令
        • 16.8 数学命令
        • 16.9 杂项命令
      • 17. 系统与管理命令
        • 17.1 分析一个系统脚本
    • 第五部分 高级话题
      • 18.正则表达式
        • 18.1正则表达式简介
        • 18.2文件名替换
      • 19. 嵌入文档
      • 20. I/O 重定向
        • 20.1 使用 exec
        • 20.2 重定向代码块
        • 20.3 应用程序
      • 21. 子shell
      • 22. 限制模式的Shell
      • 23. 进程替换
      • 24. 函数
        • 24.1 复杂函数和函数复杂性
        • 24.2 局部变量
        • 24.3 不适用局部变量的递归
      • 25. 别名
      • 26. 列表结构
      • 27. 数组
      • 28. 间接引用
      • 29. /dev 和 /proc
        • 29.1 /dev
        • 29.2 /proc
      • 30. 网络编程
      • 32. 调试
      • 33. 选项
      • 34. 陷阱
      • 36. 杂项
        • 36.1 交互和非交互shell以及脚本
        • 36.2 shell wrappers
        • 36.3 测试和比较的其他方法
        • 36.4 递归:调用自己的脚本
        • 36.5 “彩色”的脚本
        • 36.6 优化
        • 36.7 其他技巧
        • 36.8 安全问题
        • 36.9 可移植性问题
        • 36.10 Windows系统下的脚本
    • 38. 后记
      • 38.1 作者后记
      • 38.2 关于作者
      • 38.3 从哪里可以获得帮助
      • 38.4 用来制作这本书的工具
      • 38.5 致谢
      • 38.6 免责声明
  • 附录及索引
    • 参考文献
    • 附录
    • 索引
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 正文
  2. 第五部分 高级话题

20. I/O 重定向

上一页19. 嵌入文档下一页20.1 使用 exec

最后更新于5年前

这有帮助吗?

目录

有三个默认打开的文件, stdin(标准输入,键盘),stdout(标准输出, 屏幕)和 stderr(标准错误,屏幕上输出的错误信息)。这些和任何其他打开的文件都可以被重定向。重定向仅仅意味着捕获输出文件,命令,脚本,甚至是一个脚本的代码块()和() 作为另一个文件,命令,程序或脚本的输入。

每个打开的文件都有特定的文件描述符。,而 stdin,stdout,stderr 的文件描述符分别为 0,1,2。当然了,还有附件的文件描述符 3 - 9。有时候为stdin,stdout,stderr临时性的复制链接分配这些附加的文件描述符会非常有用.。这简化了复杂重定向和重组后的恢复(见)

   COMMAND_OUTPUT >
      # 重定向标准输出到一个文件.
      # 如果文件不存在则创建,否则覆盖.

      ls -lR > dir-tree.list
      # 创建了一个包含目录树列表的文件.

   : > filename
      # ">" 清空了文件.
      # 如果文件不存在,则创建了个空文件 (效果类似 'touch').
      # ":" 是个虚拟占位符, 不会有输出.

   > filename    
      # ">" 清空了文件.
      # 如果文件不存在,则创建了个空文件 (效果类似 'touch').
      # (结果和上述的 ": >" 一样, 但在某些 shell 环境中不能正常运行.)

   COMMAND_OUTPUT >>
      # 重定向标准输出到一个文件.
      # 如果文件不存在则创建,否则新内容在文件末尾追加.


      # 单行重定向命令 (只作用于本身所在的那行):
      # --------------------------------------------------------------------

   1>filename
      # 以覆盖的方式将 标准错误 重定向到文件 "filename."
   1>>filename
      # 以追加的方式将 标准输出 重定向到文件 "filename."
   2>filename
      # 以覆盖的方式将 标准错误 重定向到文件 "filename."
   2>>filename
      # 以追加的方式将 标准错误 重定向到文件 "filename."
   &>filename
      # 以覆盖的方式将 标准错误 和 标准输出 同时重定向到文件 "filename."
      # 在 bash 4 中才有这个新功能.

   M>N
     # "M" 是个文件描述符, 如果不明确指定,默认为 1.
     # "N" 是个文件名.
     # 文件描述符 "M" 重定向到文件 "N."
   M>&N
     # "M" 是个文件描述符, 如果不设置默认为 1.
     # "N" 是另一个文件描述符.

      #==============================================================================

      # 重定向 标准输出,一次一行.
      LOGFILE=script.log

      echo "This statement is sent to the log file, \"$LOGFILE\"." 1>$LOGFILE
      echo "This statement is appended to \"$LOGFILE\"." 1>>$LOGFILE
      echo "This statement is also appended to \"$LOGFILE\"." 1>>$LOGFILE
      echo "This statement is echoed to stdout, and will not appear in \"$LOGFILE\"."
      # 这些重定向命令在每行结束后自动"重置".



      # 重定向 标准错误,一次一行.
      ERRORFILE=script.errors

      bad_command1 2>$ERRORFILE       #  Error message sent to $ERRORFILE.
      bad_command2 2>>$ERRORFILE      #  Error message appended to $ERRORFILE.
      bad_command3                    #  Error message echoed to stderr,
                                      #+ and does not appear in $ERRORFILE.
      # 这些重定向命令每行结束后会自动“重置”.
	#=======================================================================
   2>&1
      # 重定向 标准错误 到 标准输出.
      # 错误信息发送到标准输出相同的位置.
        >>filename 2>&1
            bad_command >>filename 2>&1
            # 同时将 标准输出 和 标准错误 追加到文件 "filename" 中 ...
        2>&1 | [command(s)]
            bad_command 2>&1 | awk '{print $5}'   # found
            # 通过管道传递 标准错误.
            # bash 4 中可以将 "2>&1 |" 缩写为 "|&".

   i>&j
      # 重定向文件描述符 i 到 j.
      # 文件描述符 i 指向的文件输出将会重定向到文件描述符 j 指向的文件

   >&j
      # 默认的标准输出 (stdout) 重定向到 j.
      # 所有的标准输出将会重定向到 j 指向的文件.
   0< FILENAME
    < FILENAME
      # 从文件接收输入.
      # 类似功能命令是 ">", 经常会组合使用.
      #
      # grep search-word <filename


   [j]<>filename
      #  打开并读写文件 "filename" ,
      #+ 并且分配文件描述符 "j".
      #  如果 "filename" 不存在则创建.
      #  如果文件描述符 "j" 未指定, 默认分配文件描述符 0, 标准输入.
      #
      #  这是一个写指定文件位置的应用程序. 
      echo 1234567890 > File    # 写字符串到 "File".
      exec 3<> File             # 打开并分配文件描述符 3 给 "File" .
      read -n 4 <&3             # 读取 4 字符.
      echo -n . >&3             # 写一个小数点.
      exec 3>&-                 # 关闭文件描述符 3.
      cat File                  # ==> 1234.67890
      #  随机访问.



   |
      # 管道.
      # 一般是命令和进程的链接工具.
      # 类似 ">", 但更一般.
      # 在连接命令,脚本,文件和程序方面非常有用.
      cat *.txt | sort | uniq > result-file
      # 所有 .txt 文件输出进行排序并且删除复制行,
      # 最终保存结果到 "result-file".

可以用单个命令行表示输入和输出的多个重定向或管道.

command < input-file > output-file
# 或者等价:
< input-file command > output-file   # 尽管这不标准.

command1 | command2 | command3 > output-file

多个输出流可以重定向到一个文件.

ls -yz >> command.log 2>&1
#  捕获不合法选项 "yz" 的结果到文件 "command.log."
#  因为 标准错误输出 被重定向到了文件,
#+ 任何错误信息都会在这.

#  注意, 然而, 接下来的这个案例并 "不能" 同样的结果.
ls -yz 2>&1 >> command.log
#  输出一条错误信息,但是不会写入到文件.
#  恰恰的, 命令输出(这个例子里为空)写入到文件, 但错误信息只会在 标准输出 输出.

#  如果同时重定向 标准输出 和 标准错误输出,
#+ 命令的顺序不同会导致不同.

关闭文件描述符

n<&-
	关闭输入文件描述符 n.

0<&-, <&-
	关闭标准输入.

n>&-
	关闭输出文件描述符 n.

1>&-, >&-
	关闭标准输出.

子进程能继承文件描述符.这就是管道符能工作的原因.通过关闭文件描述符来防止继承 .

# 只重定向到 标准错误 到管道.

exec 3>&1                              # 保存当前 标准输出 "值".

ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # 关闭 'grep' 文件描述符 3 (但不是 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # 现在关闭它.

# 感谢, S.C.

注意

更多详情见 and .

更多关于 I/O 重定向详情见 .

在 UNIX 和 Linux 中, 数据流和周边外设() 都被看做文件.

文件描述符 仅仅是操作系统分配的一个可追踪的打开的文件号. 可以认为是一个简化的文件指针. 类似于 C 语言的 文件句柄.

当 bash 创建一个子进程的时候使用 文件描述符 5 会有问题. 例如 , 子进程继承了文件描述符 5 (详情见 Chet Ramey's 归档的 e-mail, ). 最好将这个文件描述符单独规避.

20.1 使用 exec
20.2 重定向代码块
20.3 应用程序
[1]
样例 3-1
样例 3-2
[2]
[3]
样例 20-1
样例 16-31
样例 A-14
Appendix F
[1]
device files
[2]
[3]
exec
SUBJECT: RE: File descriptor 5 is held open