• Pipelines in Shell


    本篇文章内容需要读者知道 shell 的一些语法和作用,知道 shell 的用途,和一些基本的用法。

    这里可以查看原文:Pipelines in Shell

    学习 shell 脚本必须要理解 pipeline 的概念,知道 command 的输入(input)和输出(output)的概念。只有掌握了 pipeline 的机制我们才能更好的写好 shell 脚本,本章内容详细介绍 pipeline。

    shell 中的 command 可以接受一些输入然后产生一些输出,类似与数学中的函数表达式 y = f(x),输入参数 x,得到结果 y,command 就可以看作是一个函数方程。

    标准输入、输出和错误

    stdin、stdout、stderr

    每一个程序都会接触到三个比较特殊的文件(linux 中所有东西都是文件):stdinstdoutstderr

    • stdin:standard input 的缩写,意思是标准输入,大部分程序从这里读取输入,用数字 0 表示
    • stdout:standard output 的缩写,意思是标准输出,大部分程序将输出信息写入到这个文件里,用数字 1 表示
    • stderr:standard error 的缩写,意思是标准错误,大部分程序出错了需要将错误信息写入这个文件,用数字 2 表示

    上面用了 大部分 这个修饰词,意思并不是所有的程序都会按照上面的规范去读取和输出信息,因为任何程序都可以自由选择从哪里读取输入,将输出信息写入哪里。

    这三个特殊的文件存储在 dev/ (dev 表示 device)文件夹下:

    $ ls -al /dev/std*
    lrwxrwxrwx 1 root root 15 Nov 26 20:25 /dev/stderr -> /proc/self/fd/2
    lrwxrwxrwx 1 root root 15 Nov 26 20:25 /dev/stdin -> /proc/self/fd/0
    lrwxrwxrwx 1 root root 15 Nov 26 20:25 /dev/stdout -> /proc/self/fd/1
    
    • 1
    • 2
    • 3
    • 4

    每次在 shell 中运行一个程序,shell 会将键盘与程序的标准输入关联在一起,并将标准输出和标准错误与终端显示连接在一起:

    stdin、stdout、stderr

    从上图中我们可以看到数据的流转,键盘 -> stdin 文件 -> program -> stdout/stderr -> 屏幕,这里的数据流转本质上也是 pipeline。

    pipe(|)操作符

    可以通过 | 操作符将一个命令的输出重定向到另一个命令的输入,即将一个命令的 stdout 作为 另一个命令的 stdin。动手实践一下:

    # 查看 file.txt 文件内容
    $ cat file.txt
    File
    Edit
    Selection
    view
    go
    Run
    Terminal
    help
    go
    view
    
    # 将文件中的内容排序并且去重
    $ cat file.txt | sort | uniq
    Edit
    File
    Run
    Selection
    Terminal
    go
    help
    view
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    重新用途表示 cat test.txt | sort | uniq 的数据流转:

    stdin、stdout、stderr

    输入重定向 <

    < 可以将一个程序的标准输入重定向至某个文件,例如 rev < /dev/stdin,即 rev 命令将从标准输入读取输入,所以 rev < /dev/stdin回车 与 rev 直接回车命令是等价的。

    输出重定向至文件 >>>

    • > 将一个命令的输出写入一个文件,并覆盖(override)文件内容
    • >> 将一个命令的输出内容添加(append)至文件的尾部,不删除文件原有的内容
    $ echo "Hello Shell" > test.txt
    $ cat test.txt
    Hello Shell
    $ echo "Hello Pipeline" >> test.txt
    $ cat test.txt
    Hello Shell
    Hello Pipeline
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2>2>> 表示将标准错误重定向至某个文件,2 是标准错误的文件描述符

    标准错误

    我们试着在同一个路径下创建两个相同的目录,看看会发生什么:

    $ mkdir js
    $ mkdir js
    mkdir: cannot create directory ‘js’: File exists
    
    • 1
    • 2
    • 3

    可以看到再次创建同名目录,shell 会报错,这里的错误信息就是标准错误,不是标准输出。我们可以试试使用 pipe 操作符,看能否重定向标准错误。

    测试需要使用 tr(translate characters)命令,可以将字符小写转换为大写,例如:

    $ echo 'Be quiet, this is a library!' | tr '[:lower:]' '[:upper:]'
    BE QUIET, THIS IS A LIBRARY!
    
    • 1
    • 2

    现在我们重定向我们的错误信息:

    $ mkdir js | tr '[:lower:]' '[:upper:]'
    mkdir: cannot create directory ‘js’: File exists
    
    • 1
    • 2

    可以看到 tr 命令似乎并没有接收到任何标准输入,这是因为 mkdir js 出错了,错误信息输出到了标准错误,而 | 只会重定向标准输出。

    在上面提到过 stdinstdoutstderr 都有一个文件描述符分别为 012

    那如何处理标准错误信息呢?这里有一些常规的做法:

    stdin、stdout、stderr

    • 2>&12> 用于标准错误重定向到某个文件,而 stdinstdoutstderr 是特殊的文件,所以这里表示标准错误(2)重定向到标准输出(1)
    • 2>./errors.txt:将标准错误信息重定向到某个文件,会覆盖文件原有内容
    • 2>/dev/null: 将标准错误输出到 /dev/null
    • 2>>./errors.txt: 将标准错误信息添加到某个文件
    • >output.txt 2>&1:将标准错误和标准输出都重定向到 output.txt 文件

    我们试着将创建文件夹的报错信息重定向到 error.txt 文件:

    $ mkdir js 2>error.txt
    $ cat error.txt
    mkdir: cannot create directory ‘js’: File exists
    
    • 1
    • 2
    • 3

    2>error.txt 表示重定向错误信息,所以第一次执行 mkdir js 时屏幕上并没有报错信息。

    参考

    推荐一本非常棒的 shell 学习教程:Effective Shell

    (完)

  • 相关阅读:
    配置Sublime作为Python的编辑器
    如何將人臉變漂亮(七)
    使用scp把另外一台服务器上的文件夹/文件拷贝到当前服务器
    使用Ubuntu虚拟机离线部署RKE2高可用集群
    ZedGraph设置刻度轴的颜色、刻度文本颜色以及网格线的颜色
    二叉树的存储结构
    基于QT封装海康SDK(MvCameraControl),访问控制海康相机
    OceanBase荣获OSCAR两项大奖,开源已成主流开发模式
    CSS详细基础(三)复合选择器
    208道Java中高级高频面试题(含答案)
  • 原文地址:https://blog.csdn.net/AHcola233/article/details/128058218