本篇文章内容需要读者知道 shell 的一些语法和作用,知道 shell 的用途,和一些基本的用法。
学习 shell 脚本必须要理解 pipeline 的概念,知道 command 的输入(input)和输出(output)的概念。只有掌握了 pipeline 的机制我们才能更好的写好 shell 脚本,本章内容详细介绍 pipeline。
shell 中的 command 可以接受一些输入然后产生一些输出,类似与数学中的函数表达式 y = f(x)
,输入参数 x
,得到结果 y
,command 就可以看作是一个函数方程。
每一个程序都会接触到三个比较特殊的文件(linux 中所有东西都是文件):stdin
、stdout
和 stderr
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
每次在 shell 中运行一个程序,shell 会将键盘与程序的标准输入关联在一起,并将标准输出和标准错误与终端显示连接在一起:
从上图中我们可以看到数据的流转,键盘 -> stdin 文件 -> program -> stdout/stderr -> 屏幕,这里的数据流转本质上也是 pipeline。
|
)操作符 #可以通过 |
操作符将一个命令的输出重定向到另一个命令的输入,即将一个命令的 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
重新用途表示 cat test.txt | sort | uniq
的数据流转:
<
#<
可以将一个程序的标准输入重定向至某个文件,例如 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
2>
和2>>
表示将标准错误重定向至某个文件,2
是标准错误的文件描述符
我们试着在同一个路径下创建两个相同的目录,看看会发生什么:
$ mkdir js
$ mkdir js
mkdir: cannot create directory ‘js’: File exists
可以看到再次创建同名目录,shell 会报错,这里的错误信息就是标准错误,不是标准输出。我们可以试试使用 pipe 操作符,看能否重定向标准错误。
测试需要使用 tr
(translate characters)命令,可以将字符小写转换为大写,例如:
$ echo 'Be quiet, this is a library!' | tr '[:lower:]' '[:upper:]'
BE QUIET, THIS IS A LIBRARY!
现在我们重定向我们的错误信息:
$ mkdir js | tr '[:lower:]' '[:upper:]'
mkdir: cannot create directory ‘js’: File exists
可以看到 tr 命令似乎并没有接收到任何标准输入,这是因为 mkdir js
出错了,错误信息输出到了标准错误,而 |
只会重定向标准输出。
在上面提到过 stdin
、stdout
、stderr
都有一个文件描述符分别为 0
、1
、2
。
那如何处理标准错误信息呢?这里有一些常规的做法:
2>&1
:2>
用于标准错误重定向到某个文件,而 stdin
、stdout
、stderr
是特殊的文件,所以这里表示标准错误(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
2>error.txt
表示重定向错误信息,所以第一次执行 mkdir js
时屏幕上并没有报错信息。
推荐一本非常棒的 shell 学习教程:Effective Shell。
(完)