myfreax

标准输入/标准输出/标准错误与重定向

0表示标准输入。1表示标准输出。2标准错误。您可以使用这些文件描述符来控制程序或者脚本的输入和输出

8 min read
By myfreax
标准输入/标准输出/标准错误与重定向
标准输入/标准输出/标准错误与重定向

在Linux,可以通过两种方式查看Shell命令的输出,一种是在终端屏幕显示输出,另一种将输出保存到文件。

在本教程中,我们将以实例说明Shell脚本中必不可少的知识,即标准输入、标准输出和重定向。

什么是标准输入/标准输出/标准错误

在Linux 一切都是文件,包括输入和输出。每个进程都可以同时打开九个文件描述符。

保留的文件描述符是0、1、2。当运行命令时,命令启动的进程就会自动打开三个保留的文件描述符。

0表示标准输入,全称standard input,简称stdin,默认是键盘的输入,对应的文件描述符是/proc/self/fd/0

1表示标准输出,全称standard output,简称stdout,默认是输出到屏幕,对应的文件描述符是/proc/self/fd/1

2标准错误,全称standard error,简称stderr,默认是输出到屏幕,对应的文件描述符是/proc/self/fd/2

可以使用这些文件描述符来控制命令程序或者脚本的输入和输出。你需要完全理解这三个概念。

因为它是Shell脚本或者程序的支柱。因此,我们将以实例的形式详细描述它们中的每一个,帮助你理解。

标准输入

STDIN代表标准输入,也就是文件描述符1,默认为键盘。可以使用重定向符号<指定文件作为标准输入。

如果你将标准输入替换为文件,重定向符号<会将文件数据作为标准输入传递给指定的命令。

例如命令cat < archive.tar | gzip -c > archive.tar.gz使用重定向符号<archive.tar文件作为标准输入传递给cat命令。

cat命令接收标准输入后,又将archive.tar文件内容写入标准输出,最后通过管道传递给gzip命令进行压缩。

cat < archive.tar | gzip -c > archive.tar.gz

标准输出

STDOUT代表标准输出,也就是文件描述符2,默认为屏幕。可以使用重定向符号>>>将标准输出重定向到文件。

也可以使用重定向符号>>将数据追加到指定文件。例如命令pwd >> log会将pwd命令的标准输出追加到文件log。

而重定向符号>则会使用标准输出覆盖指定文件。例如命令> filename将会清空文件filename

pwd >> log
> filename

标准错误

ls file2 > file命令尝试使用重定向>符号将标准输出重定向到文件。如果当前目录没有文件file2。

ls命令将会打印一个错误ls: cannot access 'file2': No such file or directory,这通常称为标准错误stderr

默认情况下,Shell将标准错误发送到屏幕。如果您需要将标准错误重定向到日志文件,可以使用重定向符号>/>>重定向错误。

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

重定向错误

正如引言所提到的,2是标准错误,因此我们将文件描述符2放在重定向符号之前来重定向错误。

假设当前目录不存在文件xfile,现在运行命令ls -l xfile 2> log会把错误重定向到文件log,2>表示重定向标准错误。

如您所见错误消息并没有打印在屏幕,而是写入到文件,可以运行cat命令查看文log文件的内容。

ls -l xfile 2> log
cat log

重定向错误与标准输出

要重定向标准错误和标准输出,必须在每个重定向符号之前添加正确的文件描述符。在同一命令可以使用多个重定向符号来实现标准错误和标准错误的重定向。

假设当前目录存在文件file1,但不存在文件file2。现在运行命令ls flie1 file2将会同时产生标准错误和标准输出。

出于某种原因,你可能需要标准错误写入到文件error.log,而标准输出写入文件access.log。

此时就可以使用文件描述1和重定向符号>写入到access.log文件,组合之后的符号是1>

文件描述符2和重定向符号>写入到error.log文件,组合之后的符号是2>。因此最终的命令是ls file1 file2 2> error.log 1> access.log

除此之外还可以使用&>符号将标准输出和标准错误重定向到同一个文件。例如命令ls file1 file2 &> log

你可能看到重定向标准错误与标准输出的命令,与你经常在其它教程看到的不一样。

这里为了易于理解如何重定向标准错误和标准输出,因此,这里没有说明另一个与你经常的命令,本教程最后一节会有提到。

ls file1 file2 2> error.log 1> access.log
ls file1 file2 &> log

永久重定向

输出重定向有两种方式临时重定向和永久重定向。对于临时重定向,可以使用>或者>>符号。如果您有很多数据需要重定向,可以使用exec命令进行永久重定向。

永久重定向并不是真的就一直唯一类型的重定向,可以随时使用exec命令进行修改。

永久重定向相当于为进程创建一个文件描述符,接下来运行命令的标准输出,标准错误,标准输入都使用同一文件描述符。

例如std.sh脚本将会重定向exec命令之后的所有标准输出,也就是echo生成的标准输出。如果运行cat命令查看log文件,我们将看到echo命令的标准输出。

可以多次使用exec命令多次重定向不同的文件描述符,例如命令exec 2> error.log将标准错误重定向到文件error.log

当你读到这里还是很难理解,请尝试运行std.sh脚本,理解运行运行顺序,运行cat命令查看两个文件error.loglog

#!/bin/bash
exec 1> log #永久重定向标准输出
echo "Permanent redirection"
echo "from a shell to a file."
echo "without redirecting every line"

exec 2> error.log #永久重定向标准错误
echo "Script Begining ..."
echo "Redirecting Output"
std.sh

除了使用exec命令重定向标准输出,标准错误。还可以使用exec命令重定向标准输入。默认的标准输入STDIN,也就是文件描述符1,通常是键盘。

命令exec 0< log使用log文件作为标准输入STDIN,而不是默认的键盘。通常Linux系统管理员使用这种技术来读取日志文件进行处理。

stdin.sh脚本很简单。您应该知道如何使用read 命令获取用户输入。如果将文件重定向到标准输入STDIN,read命令将尝试读取文件的内容。

#!/bin/bash
exec 0< testfile
total=1
while read line; do
	echo "#$total: $line"
	total=$(($total + 1))
done
stdin.sh

nohup 命令重定向标准错误和标准输出

有时候您可能不想看到任何输出。我们将输出重定向到黑洞,也就是空设备文件/dev/null。这种情况在使用nohup命令启动后台进程时常见。

在使用nohup命令启动后台进程时你可能见过符号2>&1,但很少使用这种方式2> /dev/null 1> /dev/null重定向到空设备文件/dev/null

其实ls -al file1 file2 2> /dev/null 1> /dev/nullls -al file1 file2 > /dev/null 2>&1是不相等的命令。

2> /dev/null 1> /dev/null是直接将标准错误重定向到空设备文件,而> /dev/null 2>&1是将标准错误先重定向到标准输出,然后再重定向到空设备文件。

ls -al file1 file2 2> /dev/null 1> /dev/null
ls -al file1 file2 > /dev/null 2>&1

如果2>&1是将标准错误信息重定向到标准输出,你可能会想问2>1结果是什么,我们可以运行命令ls -al file1 file2 2>1来验证这一点。

运行命令后你可能注意到当前目录存在文件1,运行命令cat 1你会发现标准错误都写入文件1。​

也就是说2>1会将标准错误重定向到文件1里面,所以2>&1中的&1指的是标准输出。

ls -al file1 file2 2>1
cat 1
ls: cannot access 'file2': No such file or directory

结论

现在您了解标准输入、标准输出、标准错误以及如何重定向它们。

Related Articles