在 Linux 中重定向输入和输出

CompTIACompTIABeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

引言

在本实验中,你将学习在 Linux shell 中重定向输入和输出的基本技术。你将通过操作三个标准流:标准输出 (stdout)、标准错误 (stderr) 和标准输入 (stdin),来探索如何控制命令的数据流。本实验提供重定向运算符的实践机会,使你能够保存命令输出、管理错误消息以及从文件中为命令提供输入。

在整个练习过程中,你将使用 > 运算符将命令输出发送到文件,覆盖现有内容;使用 >> 运算符将输出追加到文件,而不丢失数据。你还将学习使用 2> 来专门重定向错误消息,以及如何将标准输出和标准错误合并到单个文件中。最后,你将使用 tee 命令同时在屏幕上显示输出并将其保存到文件,并使用 < 运算符重定向标准输入,使命令从文件读取而不是从键盘读取。

使用 > 运算符重定向标准输出

在本步骤中,你将学习如何重定向命令的标准输出。在 Linux shell 中,大多数命令都会产生一些输出。默认情况下,这些输出被称为“标准输出”(Standard Output,简称 stdout),会显示在你的终端屏幕上。但是,你可以使用 > 运算符将此输出重定向到文件。这对于保存命令结果、创建日志文件或生成报告非常有用。

首先,让我们执行一个简单的命令,并在终端上查看其输出。

echo "Hello from LabEx"

你应该会在终端上直接看到以下输出:

Hello from LabEx

现在,让我们将此输出重定向到文件。我们将使用 > 运算符后跟一个文件名。这会告诉 shell 将 echo 命令的输出发送到当前目录(~/project)下的 hello.txt 文件中。

执行以下命令:

echo "Hello from LabEx" > hello.txt

请注意,这次你没有在终端上看到任何输出。这是因为输出已被发送到 hello.txt 文件。你可以使用 cat 命令来验证文件的内容:

cat hello.txt

输出将显示被重定向的文本:

Hello from LabEx

如果文件不存在,> 运算符会创建该文件。请注意,如果文件已存在,> 运算符将覆盖其全部内容,而不会发出任何警告。让我们来看看实际情况。

首先,让我们列出当前目录的内容,并将其保存到一个名为 file_list.txt 的新文件中。

ls -l > file_list.txt

现在,查看 file_list.txt 的内容:

cat file_list.txt

你将看到项目目录中文件的列表,其内容应类似于:

total 4
-rw-rw-r-- 1 labex labex  0 Jun 25 14:56 file_list.txt
-rw-rw-r-- 1 labex labex 17 Jun 25 14:56 hello.txt

现在,让我们运行另一个命令,并将其输出重定向到同一个文件 file_list.txt

echo "This is new content." > file_list.txt

如果再次检查 file_list.txt 的内容,你会发现原始文件列表已被替换。

cat file_list.txt

输出现在是:

This is new content.

这演示了 > 运算符的覆盖行为。在下一步中,你将学习如何将输出追加到文件而不覆盖它。

使用 >> 运算符追加标准输出

在本步骤中,你将学习如何向文件末尾添加输出而不删除其现有内容。在上一步中,你看到 > 运算符会覆盖目标文件。为了避免这种情况,你可以使用追加运算符 >>。此运算符对于维护运行日志文件等任务非常有用,你可以在其中随着时间的推移添加新条目。

让我们先创建一个包含一些初始内容的文件。我们将它命名为 greetings.txt

echo "Hello, this is the first line." > greetings.txt

现在,验证其内容:

cat greetings.txt

输出应为:

Hello, this is the first line.

接下来,我们不覆盖文件,而是使用 >> 运算符向其追加新的一行。

echo "This is the second line, appended." >> greetings.txt

再次查看 greetings.txt 的内容。

cat greetings.txt

这次,你将看到新的一行已添加到原始内容之后:

Hello, this is the first line.
This is the second line, appended.

>> 运算符非常适合创建日志文件。让我们创建一个名为 activity.log 的简单日志文件,并使用 date 命令向其中添加时间戳。

date > activity.log

现在,将另一个时间戳追加到同一个文件。

date >> activity.log

查看最终的 activity.log 文件,以查看两个条目。

cat activity.log

输出将显示两个时间戳,表明第二个命令追加了其输出,而不是覆盖了文件。具体时间会有所不同。

Wed Jun 25 14:56:53 CST 2025
Wed Jun 25 14:56:56 CST 2025

这展示了 >> 如何保留现有数据并将新数据添加到文件末尾,使其成为用新信息更新文件的安全方式。

使用 2> 运算符重定向标准错误

在本步骤中,你将学习如何管理错误消息。除了标准输出(stdout)之外,命令还会产生另一种称为“标准错误”(Standard Error,简称 stderr)的输出。这是一个单独的流,专门用于错误消息和诊断信息。默认情况下,stdoutstderr 都会显示在你的终端上,但你到目前为止学到的重定向运算符(>>>)仅影响 stdout

要重定向 stderr,你需要指定其文件描述符,即 2> 运算符实际上是 1> 的简写,其中 1stdout 的文件描述符。因此,要重定向 stderr,你需要使用 2>

让我们生成一个错误来演示这一点。我们将尝试列出一个不存在的文件。

ls non_existent_file

此命令将失败并在你的终端上打印错误消息:

ls: cannot access 'non_existent_file': No such file or directory

现在,让我们尝试使用标准的 > 运算符重定向它。

ls non_existent_file > output.txt

请注意,错误消息仍然打印到终端。> 运算符没有捕获它。如果你检查 output.txt 文件,你会发现它是空的。

cat output.txt

该命令没有产生任何输出,因为没有生成标准输出,只有标准错误。

现在,让我们使用 2> 将标准错误正确地重定向到一个名为 error.log 的文件。

ls non_existent_file 2> error.log

这次,终端上没有显示任何消息。错误已成功重定向。你可以查看 error.log 的内容来查看捕获的消息。

cat error.log

输出将是 ls 命令的错误消息:

ls: cannot access 'non_existent_file': No such file or directory

就像 >> 追加标准输出一样,你可以使用 2>> 将标准错误追加到文件。让我们尝试列出另一个不存在的文件,并将错误追加到我们的 error.log 中。

ls another_fake_file 2>> error.log

现在,再次检查 error.log 的内容。

cat error.log

你将看到新的错误消息已添加到文件末尾。

ls: cannot access 'non_existent_file': No such file or directory
ls: cannot access 'another_fake_file': No such file or directory

这项技术对于将正常输出与错误消息分开非常有用,它允许你记录错误以便稍后审查,而不会使你的主输出文件混乱。

将 stdout 和 stderr 重定向到单个文件

在本步骤中,你将学习如何将命令的所有输出——包括标准输出和标准错误——捕获到单个文件中。当你想要一份脚本或命令执行的完整记录时,包括发生的任何错误,这尤其有用。

让我们使用一个会产生 stdoutstderr 的命令。我们将尝试列出一个存在的文件(/etc/passwd)和一个不存在的文件(non_existent_file)。

ls -l /etc/passwd non_existent_file

你将在终端上看到两种类型的输出。第一行是标准错误,第二行是标准输出。

ls: cannot access 'non_existent_file': No such file or directory
-rw-r--r-- 1 root root 1916 Jul 18  2024 /etc/passwd

如果你尝试仅使用 > 来重定向 stdout,错误消息仍会显示在屏幕上。

ls -l /etc/passwd non_existent_file > output_only.txt

终端上的输出:

ls: cannot access 'non_existent_file': No such file or directory

output_only.txt 将只包含标准输出:

cat output_only.txt
-rw-r--r-- 1 root root 1916 Jul 18  2024 /etc/passwd

要将两个流重定向到一个文件,你可以使用 &> 运算符。这是一个方便的简写,它将标准输出(文件描述符 1)和标准错误(文件描述符 2)都发送到指定的文件。

让我们试试。我们将所有输出重定向到一个名为 combined.log 的文件。

ls -l /etc/passwd non_existent_file &> combined.log

这次,终端上没有打印任何内容。所有输出都已捕获到 combined.log 中。让我们查看其内容:

cat combined.log

你将看到文件同时包含标准输出和标准错误:

ls: cannot access 'non_existent_file': No such file or directory
-rw-r--r-- 1 root root 1916 Jul 18  2024 /etc/passwd

还有一个更传统但稍微复杂一些的语法可以达到相同的结果:> file 2>&1。让我们分解一下:

  • > file: 这会将标准输出(文件描述符 1)重定向到 file
  • 2>&1: 这会将标准错误(文件描述符 2)重定向到与标准输出(文件描述符 1)相同的位置。由于 stdout 已经指向 file,因此 stderr 也被发送到那里。

让我们尝试这种方法,将输出保存到 combined_traditional.log

ls -l /etc/passwd non_existent_file > combined_traditional.log 2>&1

同样,终端上没有输出显示。验证文件内容会显示相同的结果:

cat combined_traditional.log
ls: cannot access 'non_existent_file': No such file or directory
-rw-r--r-- 1 root root 1916 Jul 18  2024 /etc/passwd

虽然 &> 更简短且通常更受欢迎,但你会在旧脚本中经常看到 2>&1,因此理解它的作用很重要。要追加两个流,你可以使用 &>>>> file 2>&1

使用 tee 分割输出并通过 < 重定向标准输入

在本最终步骤中,你将探索两个互补的重定向概念:使用 tee 命令分割输出,以及使用 < 运算符将输入提供给文件中的命令。

使用 tee 分割输出

有时,你希望将命令的输出保存到文件,同时也在终端上查看它。>>> 运算符仅将输出重定向到文件,将其隐藏在屏幕之外。tee 命令通过分割输出,将其发送到文件和标准输出(你的屏幕),从而解决了这个问题。它的名字来源于管道中的 T 型三通接头,它将一股流分成两条路径。

让我们实际操作一下。我们将列出 /etc 目录的内容,并使用 tee 命令同时在屏幕上显示列表并将列表保存到名为 etc_listing.txt 的文件中。

ls /etc/ | tee etc_listing.txt

你将在终端上看到完整的目录列表。同时,tee 命令已将完全相同的输出写入 etc_listing.txt。你可以验证这一点:

cat etc_listing.txt

文件内容将与你在屏幕上看到的内容相匹配。

默认情况下,tee 会覆盖目标文件。要改为追加到文件,请使用 -a 选项。这对于日志记录非常有用。让我们创建一个日志文件并追加两个条目。

date | tee system_log.txt
echo "User labex performed a system check." | tee -a system_log.txt

第一个命令创建 system_log.txt 并写入当前日期。第二个命令使用 tee -a 追加新行,而不删除日期。让我们检查最终文件:

cat system_log.txt

输出将显示两行:

Wed Jun 25 14:56:53 CST 2025
User labex performed a system check.

使用 < 重定向标准输入

现在让我们看看输出重定向的反面:重定向标准输入(stdin)。许多命令,如 sortwccat,都可以从 stdin(通常是你的键盘)读取数据。< 运算符允许你指示命令从文件中获取其输入。

首先,让我们创建一个包含项目列表的简单文件。我们将它命名为 items.txt

echo "banana" > items.txt
echo "apple" >> items.txt
echo "cherry" >> items.txt

现在我们有一个包含三个未排序项目的 items.txt 文件。sort 命令可以对文本行进行排序。让我们使用 <items.txt 输入到 sort 命令。

sort < items.txt

该命令将读取 items.txt 的内容作为其输入,对其进行排序,并将结果打印到其标准输出(终端):

apple
banana
cherry

这在功能上与运行 sort items.txt 相似,但它展示了将文件重定向到命令的标准输入这一强大概念。当处理那些只能从 stdin 读取且不接受文件名作为参数的命令时,这一点变得至关重要。

作为最后一个例子,考虑 cat < items.txt。这告诉 catitems.txt 读取其输入,并且由于 cat 的作用是将其输入打印到其输出,因此它会在屏幕上显示文件的内容。

cat < items.txt

这结束了我们在 Linux 中关于基本 I/O 重定向的介绍。你现在拥有了控制命令从何处获取输入以及输出去向的工具。

总结

在本实验中,你学习了在 Linux 中重定向命令输出的基础知识。你首先使用 > 运算符将命令的标准输出(stdout)发送到文件,并注意到如果目标文件已存在,此运算符将覆盖它。为避免覆盖,你使用了 >> 运算符将输出追加到文件末尾。你还练习了使用 2> 运算符将标准错误(stderr)重定向到文件,这对于将错误消息与标准输出分开捕获非常有用。

此外,本实验演示了如何通过将 stdoutstderr 重定向到单个文件来实现全面的日志记录,从而将这些概念结合起来。你探索了 tee 命令作为一种分割输出的方法,允许它被保存到文件,同时在终端上显示。最后,你学会了使用 < 运算符重定向标准输入(stdin),使命令能够从文件而不是键盘读取其输入。