解释:Linux 中的输入、输出和错误重定向
如果您熟悉基本的 Linux 命令,您还应该学习输入输出重定向的概念。
您已经知道 Linux 命令是如何工作的。它接受输入并给出输出。这里的场景中有几个角色。让我来告诉您他们的情况。
标准输入、标准输出和标准错误
当你运行 Linux 命令时,有三个数据流在其中发挥作用:
- 标准输入 ( stdin ) 是输入数据的来源。默认情况下,stdin 是从键盘输入的任何文本。它的流 ID 为 0。
- 标准输出(stdout)是命令的结果,默认显示在屏幕上,其流ID为1。
- 标准错误 ( stderr ) 是命令产生的错误消息(如果有)。默认情况下,stderr 也会显示在屏幕上。它的流 ID 是 2。
这些流包含所谓缓冲存储器中纯文本的数据。
把它想象成水流。你需要一个水源,比如一个水龙头。你将一根管子连接到它,你可以把它储存在桶里(文件)或浇灌植物(打印)。如果需要,你也可以把它连接到另一个水龙头。基本上,你是在改变水的方向。
Linux 也有重定向的概念,您可以将 stdin、stdout 和 stderr 从其通常的目的地重定向到另一个文件或命令(甚至是打印机等外围设备)。
让我展示一下重定向的工作原理以及如何使用它。
输出重定向
第一个也是最简单的重定向形式是输出重定向,也称为 stdout 重定向。
您已经知道,默认情况下,命令的输出会显示在屏幕上。例如,我使用 ls 命令列出所有文件,这是我得到的输出:
abhishek@linux:~$ ls
appstxt new.txt static-ip.txt
使用输出重定向,您可以将输出重定向到文件。如果此输出文件不存在,则 shell 将创建它。
command > file
例如,让我将 ls 命令的输出保存到名为 output.txt 的文件中:
abhishek@linux:~$ ls > output.txt
输出文件已预先创建
你觉得这个输出文件的内容应该是什么?让我用 cat 命令给你看一个惊喜:
abhishek@linux:~$ cat output.txt
appstxt
new.txt
output.txt
static-ip.txt
你注意到了,里面包含了 output.txt 吗?我特意选择了这个例子来向你展示这一点。
在运行预期命令之前,会创建将 stdout 重定向到的输出文件。为什么?因为它需要准备好要将输出发送到的输出目标。
附加而不是破坏
一个经常被忽略的问题是,如果你重定向到已存在的文件,shell 将首先删除 ( clobber ) 该文件。这意味着输出文件的现有内容将被删除并由命令的输出替换。
您可以使用 >> 重定向语法来附加它,而不是覆盖它。
command >> file
提示:你可以使用以下命令禁止在当前 shell 会话中进行破坏:set -C
为什么要重定向 stdout?您可以存储输出以供将来参考并在以后进行分析。当命令输出太大并占据整个屏幕时,它特别有用。这就像收集日志一样。
管道重定向
在了解 stdin 重定向之前,您应该先了解管道重定向。这比较常见,而且您可能会经常使用它。
通过管道重定向,您可以将一个命令的标准输出发送到另一个命令的标准输入。
command 1 | command 2
我来举一个实际的例子。比如说,你想统计当前目录中可见文件的数量。你可以使用ls -1(它是数字 1,而不是字母 L)来显示当前目录中的文件:
abhishek@linux:~$ ls -1
appstxt
new.txt
output.txt
static-ip.txt
您可能已经知道wc 命令用于计算文件中的行数。如果将这两个命令与管道结合使用,您将获得以下结果:
abhishek@linux:~$ ls -1 | wc -l
4
使用管道时,两个命令共享同一个内存缓冲区。第一个命令的输出存储在缓冲区中,然后同一个缓冲区用作下一个命令的输入。
您将看到管道中最后一个命令的结果。这很明显,因为较早命令的标准输出被馈送到下一个命令,而不是进入屏幕。
管道重定向或管道连接不仅限于连接两个命令。您可以连接更多命令,只要一个命令的输出可以用作下一个命令的输入即可。
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
输入重定向
您可以使用 stdin 重定向将文本文件的内容传递给以下命令:
command < file
您不会看到 stdin 被大量使用。这是因为大多数 Linux 命令都接受文件名作为参数,因此通常不需要 stdin 重定向。
举个例子:
head < filename.txt
上述命令可以只是head filename.txt (不带 <)。
这并不是说 stdin 重定向完全没用。有些命令依赖它。以tr 命令为例。此命令可以做很多事情,但在下面的示例中,它将输入文本从小写转换为大写:
tr a-z A-Z < filename.txt
事实上,建议使用 stdin 而不是管道,以避免不必要地使用 cat 命令。
例如,很多人会将上面的例子与 cat 一起使用,然后对其使用 tr。坦白说,这里没有必要使用 cat。
cat filename.txt | tr a-z A-Z
合并重定向
您可以根据需要组合 stdin、stdout 和管道重定向。
例如,下面的命令列出当前目录中的所有 .txt 文件,然后对这些 .txt 文件进行计数并将输出保存到新文件。
ls *.txt | wc -l > count.txt
错误重定向
有时当您运行某些命令或脚本时,您会看到它在屏幕上显示一条错误消息。
abhishek@linux:~$ ls -l ffffff > output.txt
ls: cannot access 'ffffff': No such file or directory
在本文的开头,我提到有三种数据流,stderr 是默认显示在屏幕上的输出数据流之一。
您也可以重定向 stderr。由于它是输出数据流,因此您可以使用与 stdout 重定向相同的 > 或 >> 重定向符号。
但是,当 stdout 和 stderr 都是输出数据流时,如何区分它们呢?通过它们的流 ID(也称为文件描述符)。
数据流 | 流 ID |
---|---|
标准输入 | 0 |
标准输出 | 1 |
标准错误 | 2 |
-t, | -列表 |
-u, | -更新 |
-x, | –提取,–获取 |
-j, | –bzip2 |
-z, | –gzip、–gunzip、–ungzip |
默认情况下,当你使用输出重定向符号 > 时,它实际上意味着 1>。换句话说,你是说在这里输出 ID 为 1 的数据流。
当您必须重定向 stderr 时,可以使用其 ID,如 2> 或 2>>。这表示输出重定向针对数据流 stderr(ID 2)。
Stderr 重定向示例
让我用一些例子来说明。假设你只想保存错误,你可以使用类似这样的方法:
abhishek@linux:~$ ls fffff 2> error.txt
abhishek@linux:~$ cat error.txt
ls: cannot access 'fffff': No such file or directory
这很简单。让我们让它稍微复杂一点(并且更有用):
abhishek@linux:~$ ls -l new.txt ffff > output.txt 2> error.txt
abhishek@linux:~$ cat output.txt
-rw-rw-r-- 1 abhishek abhishek 0 May 5 10:25 new.txt
abhishek@linux:~$ cat error.txt
ls: cannot access 'ffff': No such file or directory
在上面的例子中,ls 命令尝试显示两个文件。对于一个文件,它显示成功,而对于另一个文件,它显示错误。因此,我在这里所做的是将 stdout 重定向到 ouput.txt(使用 >),将 stderr 重定向到 error.txt(使用 2>)。
您还可以将 stdout 和 stderr 重定向到同一个文件。有多种方法可以做到这一点。
在下面的例子中,我首先以追加模式将 stderr(带有 2>>)发送到 combined.txt 文件。然后,以追加模式将 stdout(带有 >>)发送到同一个文件。
abhishek@linux:~$ ls -l new.txt fff 2>> combined.txt >> combined.txt
abhishek@linux:~$ cat combined.txt
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 abhishek abhishek 0 May 5 10:25 new.txt
另一种方法(也是首选方法)是使用类似 2>&1 的方法。这可以粗略地翻译为“将 stderr 重定向到与 stdout 相同的地址”。
让我们以前面的例子为例,这次使用 2>&1 将 stdout 和 stderr 重定向到同一个文件。
abhishek@linux:~$ ls -l new.txt fff > output.txt 2>&1
abhishek@linux:~$ cat output.txt
ls: cannot access 'fff': No such file or directory
-rw-rw-r-- 1 abhishek abhishek 0 May 5 10:25 new.txt
请记住,您不能将 2>>&1 视为在追加模式下使用它。2>&1 已经进入追加模式。
您也可以先使用 2>,然后使用 1>&2 将 stdout 重定向到与 stderr 相同的文件。基本上,它是“>&”,它将一个输出数据流重定向到另一个。
概括
- 有三个数据流。一个输入,stdin(0)和两个输出数据流 stdout(1)和 stderr(2)。
- 键盘是默认的标准输入设备,屏幕是默认的输出设备。
- 输出重定向与 > 或 >> 一起使用(用于附加模式)。
- 输入重定向与 < 一起使用。
- 可以使用 2> 或 2>> 重定向 stderr。
- 可以使用 2>&1 组合 stderr 和 stdout。
既然你正在学习重定向,那么你也应该了解tee 命令。此命令使你可以同时显示到标准输出并保存到文件。
我希望你喜欢这篇关于 Linux 重定向的详细指南。如果你仍有疑问,或者有改进本文的建议,请在评论部分告诉我。