Skip to content
SRE运维进阶之路SRE运维进阶之路
github icon
  • 前端学习笔记

    20 I/O 重定向

    author iconLinuxStorycalendar icon2021年5月11日category icon
    • Linux
    tag icon
    • Bash
    timer icon大约 6 分钟

    # 20 I/O 重定向

    目录

    • 20.1 使用 execopen in new window
    • 20.2 重定向代码块open in new window
    • 20.3 应用程序open in new window

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

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

       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.
          # 这些重定向命令每行结束后会自动“重置”.
    	#=======================================================================
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
       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 指向的文件.
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
       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".
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

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

    command < input-file > output-file
    # 或者等价:
    < input-file command > output-file   # 尽管这不标准.
    
    command1 | command2 | command3 > output-file
    
    1
    2
    3
    4
    5

    更多详情见样例 16-31open in new window and 样例 A-14open in new window.

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

    ls -yz >> command.log 2>&1
    #  捕获不合法选项 "yz" 的结果到文件 "command.log."
    #  因为 标准错误输出 被重定向到了文件,
    #+ 任何错误信息都会在这.
    
    #  注意, 然而, 接下来的这个案例并 "不能" 同样的结果.
    ls -yz 2>&1 >> command.log
    #  输出一条错误信息,但是不会写入到文件.
    #  恰恰的, 命令输出(这个例子里为空)写入到文件, 但错误信息只会在 标准输出 输出.
    
    #  如果同时重定向 标准输出 和 标准错误输出,
    #+ 命令的顺序不同会导致不同.
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    关闭文件描述符

    n<&-
    	关闭输入文件描述符 n.
    
    0<&-, <&-
    	关闭标准输入.
    
    n>&-
    	关闭输出文件描述符 n.
    
    1>&-, >&-
    	关闭标准输出.
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

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

    # 只重定向到 标准错误 到管道.
    
    exec 3>&1                              # 保存当前 标准输出 "值".
    
    ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # 关闭 'grep' 文件描述符 3 (但不是 'ls').
    #              ^^^^   ^^^^
    exec 3>&-                              # 现在关闭它.
    
    # 感谢, S.C.
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    更多关于 I/O 重定向详情见 Appendix Fopen in new window.

    # 注意

    [1]open in new window 在 UNIX 和 Linux 中, 数据流和周边外设(device filesopen in new window) 都被看做文件.

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

    [3]open in new window 当 bash 创建一个子进程的时候使用 文件描述符 5 会有问题. 例如 execopen in new window, 子进程继承了文件描述符 5 (详情见 Chet Ramey's 归档的 e-mail, SUBJECT: RE: File descriptor 5 is held openopen in new window). 最好将这个文件描述符单独规避.

    edit icon编辑此页open in new window
    上次编辑于: 2022/4/27 15:33:00
    贡献者: clay-wangzhi
    上一页
    19 嵌入文档
    下一页
    第二十一章 子shell
    备案号:冀ICP备2021007336号
    Copyright © 2023 LinuxStory