myfreax
tee

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

您可以通过两种方式显示shell脚本的输出,在屏幕上显示输出或者将输出发送到文件。在本教程中我们将讨论shell脚本中必不可少的东西,即标准输入、标准输出和重定向

7 min read
By myfreax
标准输入,标准输出,标准错误与重定向

您可以通过两种方式显示shell脚本的输出,在屏幕上显示输出或者将输出发送到文件。在本教程中我们将讨论shell脚本中必不可少的东西,即标准输入、标准输出和重定向。

Linux中的一切都是文件,包括输入和输出。每个进程可以同时打开九个文件描述符。保留文件描述符0、1、2供bash shell使用。

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

您需要完全理解这三个概念,因为它们是您shell脚本或者程序的支柱。因此,我们将详细描述它们中的每一个。

标准输入

STDIN代表标准输入,也就是文件描述符1,默认为键盘。

您可以使用输入重定向符号<替换默认标准输入的键盘,并将其替换为文件,它将数据作为键盘输入发送到指定程序。

当您不带任何参数键入cat命令时,它会接受来自STDIN的输入。您键入的任何字符,cat命令都会将打印到屏幕上。

标准输出

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

如果我们有一个包含数据的文件,您可以使用这个重定向符号>>将数据追加到该文件,例如命令pwd >> file将当前目录追加到文件file中。

ls xfile > file命令尝试使用重定向>符号将输出重定向到文件。如果你的计算机没有xfile文件,命令将打印一个错误ls: cannot access 'xfile': No such file or directory。这通常称为标准错误STDERR。

默认情况下,shell将错误发送到屏幕。如果您需要将错误重定向到日志文件而不是将其发送到屏幕,您可以使用重定向符号重定向错误。

重定向错误

我们可以通过将文件描述符2放在重定向符号之前来重定向错误。例如命令ls -l xfile 2> ./myfile将错误重定向到文件。

如您所见,错误消息现在在文件中,而屏幕上什么也没有输出,你可以使用cat命令查看文文件内容myfile

重定向错误和标准输出

ls –l myfile xfile anotherfile 2> error.log 1> access.log

要重定向错误和标准输出,您必须在每个重定向符号之前添加正确的文件描述符,

ls命令结果,也就标准输出。使用文件描述1和重定向符号>写入到access.log文件中。错误消息,也就是标准错误,使用文件描述符2和重定向符好>送到写入到error.log文件中。

除此之外您还可以使用&>符号将标准输出和标准错误重定向到同一个文件 ,

例如命令ls –l myfile xfile anotherfile &> file。在这里,我们将标准错误和标准输出重定向到一个名为file的文件中。

永久重定向

输出重定向有两种方式临时重定向和永久重定向。对于临时重定向,您可以使用>或者>>符号。

如果您有很多数据需要重定向,您可以使用exec命令进行永久重定向。

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

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

#!/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"

重定向输入

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

您可以使用exec命令重定向标准输入,而不是默认的标准输入STDIN,也就是文件描述符1。通常是键盘。一些Linux系统管理员使用这种技术来读取日志文件进行处理。

exec 0< myfile命令指示shell从名为myfile的文件中获取输入而不是标准输入STDIN。

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

创建输入文件描述符

我们知道Linux有九个文件描述符,您只使用其中的3个来表示输入、输出和错误。其余六个文件描述符可用于输入和输出重定向。

我们可以使用exec命令为标准输出和标准输入分配文件描述符,要重定向输入文件描述符,请执行这些操作。

将标准输入STDIN保存到另一个文件描述符。将其重定向到文件。将标准输入STDIN恢复到其原始位置。

#!/bin/bash
exec 7<&0
exec 0<myfile
total=1
while read line; do
	echo "#$total: $line"
	total=$(($total + 1))
done
exec 0<&7
read -p "Finished? " res
case $res in
y) echo "Goodbye" ;;
n) echo "Sorry, this is the end." ;;
esac

我们将标准输入STDIN保存到文件描述符7,并将标准输入STDIN重定向到文件。遍历文件行后,STDIN恢复到其原始位置。

最后的read命令只是为了确保STDIN被还原,并且您可以正常使用键盘。

当脚本退出时,文件描述符将自动关闭。如果您想自己关闭文件描述符,请将文件描述符重定向到&-它将被关闭。

lsof 命令

lsof命令用于列出系统和后台进程所打开的文件。在Fedora等许多Linux系统上,lsof 命令位于/usr/sbin下。

这是lsof命令的一些重要选项。-p指定进程ID。-d指定文件描述符。在编写shell脚本时您可以使用$$变量获取当前进程 PID。你还可以组合使用选项-a -p -d选项。

运行下面的脚本。shell脚本将创建文件描述符4和5用于写入和6用于读取。lsof将会列出脚本进程所打开文件的描述符。

这些列包括COMMAND命令,当前进程 PID,USER 运行进程的用户,FD 文件描述符等。

#!/bin/bash
exec 4> myfile1
exec 5> myfile2
exec 6< myfile3
lsof -a -p $$ -d 0,1,2,4,5,6
COMMAND    PID          USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
myfreax    494074 myfreax.com    0u   CHR  136,0      0t0       3 /dev/pts/0
myfreax    494074 myfreax.com    1u   CHR  136,0      0t0       3 /dev/pts/0
myfreax    494074 myfreax.com    2u   CHR  136,0      0t0       3 /dev/pts/0
myfreax    494074 myfreax.com    4w   REG   8,22        0 1587981 /home/myfreax.com/myfile1
myfreax    494074 myfreax.com    5w   REG   8,22        0 1587998 /home/myfreax.com/myfile2

抑制命令输出

有时您不想看到任何输出。我们将输出重定向到黑洞即空设备/dev/null。

例如命令ls -al badfile anotherfile 2> /dev/null可以将标准错误重定向到空设备/dev/null。

您也可以使用相同的方式清空文件,例如命令cat /dev/null > myfile。这将会清空文件的内容。

现在您了解了输入、输出、如何重定向它们、如何创建文件描述符以及重定向到它。

Related Articles