美文网首页
shell 入门 05 呈现数据

shell 入门 05 呈现数据

作者: wjundong | 来源:发表于2022-09-21 17:15 被阅读0次

    呈现数据

    标准文件描述符

    Linux系统将每个对象当作文件处理。这包括输入和输出进程。Linux用文件描述符(file
    descriptor)来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开
    的文件。每个进程一次最多可以有九个文件描述符。出于特殊目的,bash shell保留了前三个文
    件描述符(0、1和2)

    • 0 STDIN 标准输入
    • 1 STDOUT 标准输出
    • 2 STDERR 标准错误

    这三个特殊文件描述符会处理脚本的输入和输出。shell用它们将shell默认的输入和输出导向到相应的位置。

    # 1. STDIN 重定向
    cat < testfile
    
    # 2. STDOUT 重定向
    ls -l > test2 
    
    # 你也可以将数据追加到某个文件。这可以用>>符号来完成
    who >> test2 
    
    # 但是,如果你对脚本使用了标准输出重定向,你会遇到一个问题。
    # 当命令生成错误消息时,shell并未将错误消息重定向到输出重定向文件
    ls -al badfile > test3
    # shell对于错误消息的处理是跟普通输出分开的。如果你创建了在后台模式下运行的shell脚
    # 本,通常你必须依赖发送到日志文件的输出消息。用这种方法的话,如果出现了错误信息,这些
    # 信息是不会出现在日志文件中的。你需要换种方法来处理
    
    # 3. STDERR 
    # shell通过特殊的STDERR文件描述符来处理错误消息。STDERR文件描述符代表shell的标准错
    # 误输出。shell或shell中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。
    # 默认情况下,STDERR文件描述符会和STDOUT文件描述符指向同样的地方(尽管分配给它们
    # 的文件描述符值不同)。也就是说,默认情况下,错误消息也会输出到显示器输出中。
    # 但从上面的例子可以看出,STDERR并不会随着STDOUT的重定向而发生改变。使用脚本时,
    # 你常常会想改变这种行为,尤其是当你希望将错误消息保存到日志文件中的时候。
    # 你已经知道如何用重定向符号来重定向STDOUT数据。重定向STDERR数据也没太大差别,只
    # 要在使用重定向符号时定义STDERR文件描述符就可以了。有几种办法实现方法
    
    # 只重定向错误
    # 可以选择只重定向错误消息,将文件描述符值放在重定向符号前。该值必须紧紧地放在重定向符号前,否则不会工作
    ls -al badfile 2> output.txt
    
    # 重定向错误和数据
    # 如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据
    # 所对应的文件描述符,然后指向用于保存数据的输出文件
    ls -al test badtest 2> test1 1> test2
    
    # 另外,如果愿意,也可以将STDERR和STDOUT的输出重定向到同一个输出文件。为此bash shell提供了特殊的重定向符号&>
    # 为了避免错误信息散落在输出文件中,相较于标准输出,bash shell自动赋予了错误消息更高的优先级。这样你能够集中浏览错误信息了
    ls -al test badtest &> test1
    
    

    在脚本中重定向输出

    可以在脚本中用STDOUT和STDERR文件描述符以在多个位置生成输出,只要简单地重定向相
    应的文件描述符就行了。有两种方法来在脚本中重定向输出:

    • 临时重定向行输出
    • 永久重定向脚本中的所有命令
    # 1. 临时重定向
    # 如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR
    # 在重定向到文件描述符时,你必须在文件描述符数字之前加一个&
    # 下面 STDOUT 显示的文本显示在了屏幕上,而发送给STDERR的echo语句的文本则被重定向到了输出文件
    # ./demo.sh 2> test
    echo "This is an error" >&2 
    echo "This is normal output"
    
    # 2. 永久重定向
    # 如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐。取而代之,你可
    # 以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符
    # exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所有输出会被重定向到文件
    exec 1> testout 
    echo "This is a test of redirecting all output" 
    
    # 可以在脚本执行过程中重定向STDOUT
    exec 2> testerror 
    echo "This is the start of the script" 
    echo "now redirecting all output to another location" 
    exec 1> testout 
    echo "This output should go to the testout file" 
    echo "but this should go to the testerror file" >&2
    
    # 一旦重定向了STDOUT或STDERR,就很难再将它们重定向回原来的位置。如果你需要在重定
    # 向中来回切换的话,有个办法可以用
    
    

    在脚本中重定向输入

    # 这个命令会告诉shell它应该从文件testfile中获得输入,而不是STDIN
    exec 0< testfile
    count=1
    while read line; do
        echo "Line #$count: $line"
        count=$(($count + 1))
    done
    

    创建自己的重定向

    在脚本中重定向输入和输出时,并不局限于这3个默认的文件描述符。我曾提到过,在shell
    中最多可以有9个打开的文件描述符。其他6个从3~8的文件描述符均可用作输入或输出重定向。
    你可以将这些文件描述符中的任意一个分配给文件,然后在脚本中使用它们。本节将介绍如何在
    脚本中使用其他文件描述符。

    # 1. 创建输出文件描述符
    # 可以用exec命令来给输出分配文件描述符。和标准的文件描述符一样,一旦将另一个文件
    # 描述符分配给一个文件,这个重定向就会一直有效,直到你重新分配。
    # 将文件描述符 3 重定向到 test13out 文件, 然后在行中重定向输出到文件描述符 3
    exec 3> test13out 
    echo "This should display on the monitor" 
    echo "and this should be stored in the file" >&3 
    echo "Then this should be back on the monitor"
    
    # 也可以不用创建新文件,而是使用exec命令来将输出追加到现有文件中
    exec 3>> test13out
    
    # 2. 重定向文件描述符
    # 现在介绍怎么恢复已重定向的文件描述符。你可以分配另外一个文件描述符给标准文件描述
    # 符,反之亦然。这意味着你可以将STDOUT的原来位置重定向到另一个文件描述符,然后再利用
    # 该文件描述符重定向回STDOUT。听起来可能有点复杂,但实际上相当直接。这个简单的例子能
    # 帮你理清楚。这里文件描述符3 相当于一个中间变量, 存储了文件描述符1 的 old 位置, 之后再将其恢复
    exec 3>&1 
    exec 1>test14out 
    echo "This should store in the output file" 
    echo "along with this line."
    exec 1>&3 
    echo "Now things should be back to normal"
    
    # 3. 创建输入文件描述符
    # 可以用和重定向输出文件描述符同样的办法重定向输入文件描述符。在重定向到文件之前,
    # 先将STDIN文件描述符保存到另外一个文件描述符,然后在读取完文件之后再将STDIN恢复到它原来的位置
    exec 6<&0
    exec 0<testfile
    count=1
    while read line; do
        echo "Line #$count: $line"
        count=$(($count + 1))
    done
    
    exec 0<&6
    read -p "Are you done now? " answer
    
    case $answer in
        Y | y) echo "Goodbye" ;;
        N | n) echo "Sorry, this is the end." ;;
    esac
    
    # 4. 创建读写文件描述符
    # 尽管看起来可能会很奇怪,但是你也可以打开单个文件描述符来作为输入和输出。可以用同
    # 一个文件描述符对同一个文件进行读写。
    # 不过用这种方法时,你要特别小心。由于你是对同一个文件进行数据读写,shell会维护一个
    # 内部指针,指明在文件中的当前位置。任何读或写都会从文件指针上次的位置开始。如果不够小
    # 心,它会产生一些令人瞠目的结果。看看下面这个例子, 将文件描述符 3 重定向输入输出到文件,
    # 读取一行时还是正常的, 但是输出后会从第二行开头开始, 从而覆盖了原有的数据.
    exec 3<>testfile
    read line <&3
    echo "Read: $line"
    echo "This is a test line" >&3
    
    # 5. 关闭文件描述符
    # 如果你创建了新的输入或输出文件描述符,shell会在脚本退出时自动关闭它们。然而在有些
    # 情况下,你需要在脚本结束前手动关闭文件描述符。要关闭文件描述符,将它重定向到特殊符号 &-
    # 一旦关闭了文件描述符,就不能在脚本中向它写入任何数据,否则shell会生成错误消息。
    # 在关闭文件描述符时还要注意另一件事。如果随后你在脚本中打开了同一个输出文件,shell
    # 会用一个新文件来替换已有文件。这意味着如果你输出数据,它就会覆盖已有文件
    exec 3> test17file 
    echo "This is a test line of data" >&3 
    exec 3>&-
    cat test17file
    exec 3> test17file
    echo "This'll be bad" >&3
    

    心得: 将某个文件描述符重定向到某个文件或文件描述符格式是

    [fd1](< OR >)[&](fd2)
    

    [ ] 代表其中内容可能忽略, 若重定向到文件描述符需多加 & 且文件描述符和 & 之间不能有空格, > 为重定向输出, < 为重定向输入, fd1 若忽略不写, 直接些后面的重定向符号的话, < 默认为STDIN, > 默认为STDOUT。比如

    • > file 最常见的情况, 因为忽略了 fd1 实际上等价于 0>file 表示将标准输出重定向到文件.
    • 6<&0 将文件描述符 6 重定向输入到文件描述符 0, 这时文件描述符 6 和 0 指向同一个输入设备且位置相同。若0原来指向键盘输入, 则 6 也指向了键盘输入, 向 6 执行 read 会从键盘中获取数据。
    • 0<testfile 将文件描述0(即标准输入)重定向到 testfile 文件, 这时标准输入被指向为 testfile 文件, 向 0 执行 read 会从该文件中读取数据。因为 0 是STDIN, 因此前面文件描述符可忽略不写也是等价的 <testfile
    • 2> test13out 将文件描述符 2 重定向到 test13out 文件, 即将标准错误输出重定向到文件, 从而在程序输出错误时,错误信息被存放到该文件。
    • >&2 忽略了 fd1 且符号为重定向输出 >, 因此等价于 0>&2 即将标准输出重定向到标准错误, 可用于将程序中默认输出信息重定向到 STDERR,
    • 3<>testfile 将文件描述符重定向输入输出到文件 testfile, 这时可以同时对 3 进行读写就相当于对 testfile 文件的读写.

    列出打开的文件描述符

    阻止命令输出

    有时候,你可能不想显示脚本的输出。这在将脚本作为后台进程运行时很常见(参见第16
    章)。如果在运行在后台的脚本出现错误消息,shell会通过电子邮件将它们发给进程的属主。这
    会很麻烦,尤其是当运行会生成很多烦琐的小错误的脚本时。
    要解决这个问题,可以将STDERR重定向到一个叫作null文件的特殊文件。null文件跟它的名
    字很像,文件里什么都没有。shell输出到null文件的任何数据都不会保存,全部都被丢掉了。
    在Linux系统上null文件的标准位置是/dev/null。你重定向到该位置的任何数据都会被丢掉,
    不会显示

    ls -al badfile test16 2> /dev/null 
    

    相关文章

      网友评论

          本文标题:shell 入门 05 呈现数据

          本文链接:https://www.haomeiwen.com/subject/ruowortx.html