4

Linux中的输入、输出和错误重定向

 1 year ago
source link: https://www.51cto.com/article/722462.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
3631c8c77562b1fd949461f5951e5359655f32.jpg

如果你熟悉基本的 Linux 命令,还应该学习输入输出重定向的概念。

我们都知道 Linux 命令的功能,它接受一个输入,然后给你一个输出。在这里起作用的包含一些重要的角色,我们今天就来介绍一下这些角色。

stdin, stdout 和 stderr

当你运行 Linux 命令时,有三个数据流在其中起作用:

  • stdin:(Standard input,标准输入)是输入数据的源。默认情况下,stdin 是从键盘输入的任何文本,它的流 ID(stream ID) 为 0;
  • stdout:(Standard output,标准输出)是命令的输出结果。默认情况下,它会显示在屏幕上,它的流 ID(stream ID) 为 1;
  • stderr:(Standard error,标准错误)是命令产生的错误消息(如果有)。默认情况下,屏幕上也会显示 stderr。它的流 ID(stream ID)是2。

这些流包含存储在内存缓冲区(buffer memory)中的纯文本数据。

335872449c2c182df7a741118da2b969826be0.jpg

把它想象成一个水流,你需要水源,比如水龙头,用管道连接到它,可以将其存储在水桶(文件)中,也可以给植物浇水(打印)。如果需要,还可以将其连接到另外一个水龙头上,也就是改变水的流向(重定向)。

Linux 中也有这种重定向的概念。你可以将 stdin, stdout 和 stderr 从其原本的目标,重定向到另一个文件或命令(甚至是打印机等外围设备)。

接下来我们来介绍一下重定向是如何工作的,以及如何使用它。

输出重定向

13879f2162bddd75d53778bd55796c3b865e18.jpg

第一种也是最简单的重定向形式是输出重定向,也称为标准输出重定向。

默认情况下,命令的输出是显示在屏幕上。比如,我使用 ls 命令列出当前目录下的所有文件:

[gliu@fedora work]$ ls
appstxt  new.txt  static-ip.txt

通过输出重定向,可以将输出重定向到文件。如果此输出文件不存在,那么 shell 将创建它。

command > file

比如,我们将上述 ls 命令的输出保存到名为 output.txt 的文本文件中:

[gliu@fedora work]$ ls > output.txt

输出文件是预先创建的

那么这个 output.txt 文件的内容是什么呢?我们用 cat 命令来看一下:

[gliu@fedora work]$ cat output.txt
appstxt
new.txt
output.txt
static-ip.txt

有没有注意到里面也包含 output.txt?将输出重定向输出到的文件(output.txt)是在运行预期命令之前创建的。为什么呢?因为它需要准备好输出的目的地,输出将被发送到该目的地。

追加而不是删除

一个经常被忽略的问题是,如果重定向到一个已经存在的文件,shell 将首先删除该文件。这意味着输出文件的现有内容将被删除,并替换为命令的输出。

如果不想删除原有的内容,而只是追加,那么可以使用 >> 重定向语法:

command >> file

你可以在当前的 shell 会话中禁止删除,使用 set -C

将输出重定向到文件,可以将输出的内容保存起来以供将来参考;另外如果输出的内容太多,占用了大篇幅的屏幕时,将内容保存到文件,就更方便查看和分析了,这就像收集日志文件一样。

管道重定向

e1070f9266a96c538225217631c8ffe3aa7941.jpg

在介绍 stdin 重定向之前,我们先来了解一下管道重定向,这是更加常见的,我们会经常使用管道重定向。

关于管道重定向,可以参阅我们先前的文章:Linux 中的管道是什么?管道重定向是如何工作的?

通过管道重定向,可以将命令的标准输出发送到另一个命令的标准输入。

command 1 | command 2

我们来举个例子,如果我们要查看当前目录中文件的数量,可以使用 ls -1(注意是数字1,不是字母L)来显示当前目录中的文件:

[gliu@fedora work]$ ls -1
appstxt
new.txt
output.txt
static-ip.txt

我们知道 wc 命令用于计算文件中的行数,所以我们可以结合这个命令,如下:

[gliu@fedora work]$ ls -1 | wc -l
4

使用管道,两个命令共享相同的内存缓冲区,第一个命令的输出存储在缓冲区中,然后该缓冲区将用作下一个命令的输入。

你将看到管道中最后一个命令的结果。这一点很明显,因为先前命令的 stdout 被重定向到下一个命令,而不是打印在屏幕上。

管道重定向或管道不限于仅连接两个命令,你也可以连接多个命令,只要一个命令的输出可用作下一个命令输入。

command_1 | command_2 | command_3 | command_4

请注意,stdout/stdin是一块数据,而不是文件名

一些新的Linux用户在使用重定向时会感到困惑,如果命令返回一组文件名作为输出,则不能将这些文件名用作参数。

比如,使用 find 命令查找扩展名为 .txt 的文件,无法通过管道将查找到的这些文件移动到新的目录,不能这样操作:

find . -type f -name "*.txt" | mv destination_directory

这就是为什么我们经常会看到 find 命令与 exec 或 xargs 命令组合使用的原因。这些命令可以将大量的文本“文件名”转换为文件名,且可作为参数传递。

find . -type f -name "*.txt" | xargs -t -I{} mv {} ../new_dir

关于find 与 exec 或 xargs 命令组合使用的相关内容,可参考我们先前的文章:

find 与 exec 命令的结合,是一个功能强大的搜索工具

如何在Linux中使用xargs命令

输入重定向

38d7bb81402458a5ef721645f191d902fdedf1.jpg

使用 stdin 重定向可以将文本文件的内容传递给终端命令:

command < file

但是这种并不常用,因为大多数 Linux 命令都可以接受文件名作为参数,因此通常不需要 stdin 重定向。比如:

head < filename.txt

上面的命令可以直接写为:head filename.ext(也就是不用重定向符号 <)。

也不是说 stdin 重定向完全没有用,有些命令是依赖于它的。以 tr 命令为例,这个命令可以做很多事情,但在下面的例子中,它将输入文本从小写转为大写:

tr a-z A-Z < filename.txt

事实上,建议在管道上使用标准输入重定向,以避免不必要地使用 cat 命令。

比如上面的例子,很多人就习惯使用 cat,然而这里并没有必要使用cat:

cat filename.txt | tr a-z A-Z

合并重定向

你可以根据需要组合使用 stdin,stdout 和管道重定向。

比如,下面的命令列出当前目录下所有的 txt 文件,然后统计一下文件的总数,并将这个结果保存到一个新文件中:

ls *.txt | wc -l > count.txt

错误重定向

有时候,当你运行一些命令或脚本时,会在屏幕上看到一条错误信息:

[gliu@fedora work]$ ls -l ffffff > output.txt
ls: cannot access 'ffffff': No such file or directory

在本文的开头,我们提到过有三种数据流,stderr 是其中之一,它默认将输出显示在屏幕上。

你也可以重定向 stderr。由于它是一个输出数据流,因此可以使用与标准输出重定向相同的 > 或 >> 重定向符号。

但是,当 stdout 和 stderr 都作为输出数据流时,如何区分它们呢?通过它们的流 ID(stream ID,也称为文件描述符)。

Data stream

stream ID

stdin

stdout

stderror

-list

-update

–extract, –get

–bzip2

–gzip, –gunzip, –ungzip

默认情况下,当你使用输出重定向符号 > 时,它实际上是 1 >。换句话说,ID 为 1 的数据流是在这里输出。

所以当你要重定向 stderr 时,可以使用它的ID,比如 2> 或者 2>>。这表示输出重定向用于数据流 stderr(ID为2)。

stderr 重定向示例

我们来举几个例子。假如我们只想要保存错误信息,那么可以这样:

[gliu@fedora work]$ ls fffff 2> error.txt
[gliu@fedora work]$ cat error.txt
ls: cannot access 'fffff': No such file or directory

这个很简单。我们再来个稍微复杂一点的(并且很有用的):

[gliu@fedora work]$ ls -l new.txt ffff > output.txt 2> error.txt
[gliu@fedora work]$ cat output.txt
-rw-rw-r-- 1 gliu gliu 0 May  5 10:25 new.txt
[gliu@fedora work]$ cat error.txt
ls: cannot access 'ffff': No such file or directory

在上面的例子中,ls 命令尝试显示两个文件的信息。其中一个文件能成功,另一个会出错。所以我在这里做的是将 stdout 输出重定向到 output.txt 文件中,将 stderr 重定向到 error.txt 中(使用 2>)。

此外,我们还可以将 stdout 和 stderr 重定向到同一个文件,是有办法做到这一点的。

在下面的例子中,我使用追加模式(append mode)将 stderr 重定向到文件 combined.txt 中(使用 2>>);然后,同样使用追加模式将标准输出 stdout 重定向到同一个文件 combined.txt 中(使用 >>):

[gliu@fedora work]$ ls -l new.txt fff 2>> combined.txt >> combined.txt
[gliu@fedora work]$ cat combined.txt
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 gliu gliu 0 May  5 10:25 new.txt

另一种方法,也是首选的方法,是使用类似于 2>&1 的东西,可以大致的翻译为“将 stderr 重定向到与 stdout 相同的地址中”。

我们以前面的示例为例,这次使用 2>&1 将 stdout 和 stderr 重定向到同一个文件:

[gliu@fedora work]$ ls -l new.txt fff > output.txt 2>&1
[gliu@fedora work]$ cat output.txt
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 gliu gliu 0 May  5 10:25 new.txt

在这里需要注意的一点是,不能想当然的以为 2>>&1 为追加模式,因为 2>&1 本身就是追加模式。

此外,你也可以先使用 2>,然后使用 1>&2 将 stdout 重定向到与 stderr 相同的文件上。基本上,>& 是将一个输出数据流重定向到另一个上。

我们来总结一下

1)有三种数据流,其中一个是输入数据流 stdin(0),两个输出数据流为 stdout(1) 和 stderr(2);

2)键盘输入是默认的标准输入设备,屏幕是默认的输出设备;

3)输出重定向使用 > 或者 >>(用于追加模式);

4)输入重定向使用 <;

5)stderr 可以使用 2> 或者 2>>;

6)stderr 和 stdout 可以组合为:2>&1。

至此我们了解了关于重定向的相关知识,那么为了更加深入的学习,还可以了解一下 tee 命令,该命令可以将数据显示到标准输出中,同时保存到文件中。我们稍后会分享这个命令的用法。

以上就是本次分享全部内容,欢迎讨论。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK