呈现数据 (shell12)

20 篇文章 1 订阅
本文详细介绍了Linux中的文件描述符,包括STDIN、STDOUT和STDERR的用途,以及如何重定向错误输出、合并输出和输入。讨论了在脚本中临时和永久重定向输出和输入的方法,创建新的文件描述符,以及如何关闭文件描述符。还涵盖了如何使用mktemp创建临时文件和目录,以及如何使用tee命令进行日志记录。
摘要由CSDN通过智能技术生成

呈现数据

文件描述符

STDIN

STDIN文件描述符代表shell的标准输入。对终端界面来说,标准输入是键盘。 shell从STDIN文件描述符对应的键盘获得输入,在用户输入时处理每个字符。
在使用输入重定向符号( <)时, Linux会用重定向指定的文件来替换标准输入文件描述符。它会读取文件并提取数据,就如同它是键盘上键入的

STDOUT

STDOUT文件描述符代表shell的标准输出。在终端界面上,标准输出就是终端显示器。 shell的所有输出(包括shell中运行的程序和脚本)会被定向到标准输出中,也就是显示器。

STDERR

shell通过特殊的STDERR文件描述符来处理错误消息。 STDERR文件描述符代表shell的标准错误输出。 shell或shell中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。
默认情况下, STDERR文件描述符会和STDOUT文件描述符指向同样的地方(尽管分配给它们的文件描述符值不同)。也就是说,默认情况下,错误消息也会输出到显示器输出中。

重定向错误

只重定向错误
ls -al badfile 2> test4
重定向错误和数据
ls -al test test2 test3 badtest 2> test6 1> test7

#将STDERR和STDOUT的输出重定向到同一个输出文件,特殊的重定向符号&>
ls -al test test2 test3 badtest &> test7

当使用&>符时,命令生成的所有输出都会发送到同一位置,包括数据和错误。你会注意到其中一条错误消息出现的位置和预想中的不一样。 badtest文件(列出的最后一个文件)的这条错误消息出现在输出文件中的第二行。为了避免错误信息散落在输出文件中,相较于标准输出, bash shell自动赋予了错误消息更高的优先级。这样你能够集中浏览错误信息了。

在脚本中重定向输出

临时重定向

如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR。你所需要做的是使用输出重定向符来将输出信息重定向到STDERR文件描述符。在重定向到文件描述符时,你必须在文件描述符数字之前加一个&

#这行会在脚本的STDERR文件描述符所指向的位置显示文本,而不是通常的STDOUT。
echo "This is an error message" >&2
#!/bin/bash
# testing STDERR messages
echo "This is an error" >&2
echo "This is normal output"



./test8 2> test9
This is normal output
cat test9
This is an error
永久重定向

如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐。取而代之,你可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。

#!/bin/bash
# redirecting all output to a file
exec 1>testout
echo "This is a test of redirecting all output"
echo "from a script to another file."
echo "without having to redirect every individual line"



./test10
cat testout
This is a test of redirecting all output
from a script to another file.
without having to redirect every individual line

exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所有输出会被重定向到文件。

在脚本中重定向输入

你可以使用与脚本中重定向STDOUT和STDERR相同的方法来将STDIN从键盘重定向到其他位置。 exec命令允许你将STDIN重定向到Linux系统上的文件中

#!/bin/bash
# redirecting file input
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done


./test12
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
创建自己的重定向
创建输出文件描述符

可以用exec命令来给输出分配文件描述符。和标准的文件描述符一样,一旦将另一个文件描述符分配给一个文件,这个重定向就会一直有效,直到你重新分配。

#!/bin/bash
# using an alternative file descriptor
exec 3>test13out
echo "This should display on the monitor"
echo "and this should be stored in the file" >&3
echo "Then this should be back on the monitor"


./test13
This should display on the monitor
Then this should be back on the monitor

cat test13out
and this should be stored in the file

也可以不用创建新文件,而是使用exec命令来将输出追加到现有文件中。

#现在输出会被追加到test13out文件,而不是创建一个新文件
exec 3>>test13out
重定向文件描述符
#!/bin/bash
# storing STDOUT, then coming back to it
exec 3>&1
exec 1>test14out
echo "This should store in the output file"
echo "along with this line."
exec 1>&3
echo "Now things should be back to normal"

./test14
Now things should be back to normal
$ cat test14out
This should store in the output file
along with this line.

首先,脚本将文件描述符3重定向到文件描述符1的当前位置,也就是STDOUT。这意味着任何发送给文件描述符3的输出都将出现在显示器上。
第二个exec命令将STDOUT重定向到文件, shell现在会将发送给STDOUT的输出直接重定向到输出文件中。但是,文件描述符3仍然指向STDOUT原来的位置,也就是显示器。如果此时将输出数据发送给文件描述符3,它仍然会出现在显示器上,尽管STDOUT已经被重定向了。在向STDOUT(现在指向一个文件)发送一些输出之后,脚本将STDOUT重定向到文件描述符3的当前位置(现在仍然是显示器)。这意味着现在STDOUT又指向了它原来的位置:显示器。
这个方法可能有点叫人困惑,但这是一种在脚本中临时重定向输出,然后恢复默认输出设置的常用方法。

创建输入文件描述符
#!/bin/bash
# redirecting input file descriptors
exec 6<&0
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
exec 0<&6
read -p "Are you done now? " answer
case $answer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, this is the end.";;
esac

./test15
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
Are you done now? y
Goodbye

文件描述符6用来保存STDIN的位置。然后脚本将STDIN重定向到一个文件。read命令的所有输入都来自重定向后的STDIN(也就是输入文件)。
在读取了所有行之后,脚本会将STDIN重定向到文件描述符6,从而将STDIN恢复到原先的位置。该脚本用了另外一个read命令来测试STDIN是否恢复正常了。这次它会等待键盘的输入。

创建读写文件描述符

可以用同一个文件描述符对同一个文件进行读写。

不过用这种方法时,你要特别小心。由于你是对同一个文件进行数据读写, shell会维护一个内部指针,指明在文件中的当前位置。任何读或写都会从文件指针上次的位置开始。如果不够小心,它会产生一些令人瞠目的结果。

#!/bin/bash
# testing input/output file descriptor
exec 3<> testfile
read line <&3
echo "Read: $line"
echo "This is a test line" >&3

cat testfile
This is the first line.
This is the second line.
This is the third line.


./test16
Read: This is the first line.
$ cat testfile
This is the first line.
This is a test line
ine.
This is the third line.

在运行脚本时,一开始还算正常。输出内容表明脚本读取了testfile文件中的第一行。但如果你在脚本运行完毕后,查看testfile文件内容的话,你会发现写入文件中的数据覆盖了已有的数据。

当脚本向文件中写入数据时,它会从文件指针所处的位置开始。 read命令读取了第一行数据,所以它使得文件指针指向了第二行数据的第一个字符。在echo语句将数据输出到文件时,它会将数据放在文件指针的当前位置,覆盖了该位置的已有数据。

关闭文件描述符

要关闭文件描述符,将它重定向到特殊符号&-

exec 3>&-
#!/bin/bash
# testing closing file descriptors
exec 3> test17file
echo "This is a test line of data" >&3
exec 3>&-
echo "This won't work" >&3

./badtest
./badtest: 3: Bad file descriptor

一旦关闭了文件描述符,就不能在脚本中向它写入任何数据,否则shell会生成错误消息。

在关闭文件描述符时还要注意另一件事。如果随后你在脚本中打开了同一个输出文件, shell会用一个新文件来替换已有文件。这意味着如果你输出数据,它就会覆盖已有文件。

#!/bin/bash
# testing closing file descriptors
exec 3> test17file
echo "This is a test line of data" >&3
exec 3>&-
cat test17file
exec 3> test17file
echo "This'll be bad" >&3

./test17
This is a test line of data

cat test17file
This'll be bad

在向test17file文件发送一个数据字符串并关闭该文件描述符之后,脚本用了cat命令来显示文件的内容。到目前为止,一切都还好。下一步,脚本重新打开了该输出文件并向它发送了另一个数据字符串。当显示该输出文件的内容时,你所能看到的只有第二个数据字符串。 shell覆盖了原来的输出文件。

$$

特殊环境变量$$( shell会将它设为当前PID)

列出打开的文件描述符

lsof命令会列出整个Linux系统打开的所有文件描述符。

-p,允许指定进程ID( PID),-d允许指定要显示的文件描述符编号,-a选项用来对其他两个选项的结果执行布尔AND运算

阻止命令输出

在Linux系统上null文件的标准位置是/dev/null。你重定向到该位置的任何数据都会被丢掉,不会显示。

ls -al > /dev/null
ls -al badfile test16 2> /dev/null

也可以在输入重定向中将/dev/null作为输入文件。由于/dev/null文件不含有任何内容,程序员通常用它来快速清除现有文件中的数据,而不用先删除文件再重新创建。

cat testfile
This is the first line.
This is the second line.
This is the third line.

cat /dev/null > testfile
cat testfile

创建临时文件

创建本地临时文件

默认情况下, mktemp会在本地目录中创建一个文件。要用mktemp命令在本地目录中创建一个临时文件,你只要指定一个文件名模板就行了。模板可以包含任意文本文件名,在文件名末尾加上6个X就行了。

mktemp testing.XXXXXX

ls -al testing*
-rw------- 1 rich rich 0 Oct 17 21:30 testing.UfIi13

mktemp命令会用6个字符码替换这6个X,从而保证文件名在目录中是唯一的。你可以创建多个临时文件,它可以保证每个文件都是唯一的。

在脚本中使用mktemp命令时,可能要将文件名保存到变量中,这样就能在后面的脚本中引用了。

#!/bin/bash
# creating and using a temp file
tempfile=$(mktemp test19.XXXXXX)
exec 3>$tempfile
echo "This script writes to temp file $tempfile"
echo "This is the first line" >&3
echo "This is the second line." >&3
echo "This is the last line." >&3
exec 3>&-
echo "Done creating temp file. The contents are:"
cat $tempfile
rm -f $tempfile 2> /dev/null

./test19
This script writes to temp file test19.vCHoya
Done creating temp file. The contents are:
This is the first line
This is the second line.
This is the last line.


ls -al test19*
-rwxr--r-- 1 rich rich 356 Oct 29 22:03 test19*
在/tmp 目录创建临时文件

-t选项会强制mktemp命令来在系统的临时目录来创建该文件。在用这个特性时, mktemp命令会返回用来创建临时文件的全路径,而不是只有文件名。

#!/bin/bash
# creating a temp file in /tmp
tempfile=$(mktemp -t tmp.XXXXXX)
echo "This is a test file." > $tempfile
echo "This is the second line of the test." >> $tempfile
echo "The temp file is located at: $tempfile"
cat $tempfile
rm -f $tempfile

./test20
The temp file is located at: /tmp/tmp.Ma3390
This is a test file.
This is the second line of the test.

在mktemp创建临时文件时,它会将全路径名返回给变量。这样你就能在任何命令中使用该值来引用临时文件了。

创建临时目录

-d选项告诉mktemp命令来创建一个临时目录而不是临时文件。这样你就能用该目录进行任何需要的操作了,比如创建其他的临时文件。

#!/bin/bash
# using a temporary directory
tempdir=$(mktemp -d dir.XXXXXX)
cd $tempdir
tempfile1=$(mktemp temp.XXXXXX)
tempfile2=$(mktemp temp.XXXXXX)
exec 7> $tempfile1
exec 8> $tempfile2
echo "Sending data to directory $tempdir"
echo "This is a test line of data for $tempfile1" >&7
echo "This is a test line of data for $tempfile2" >&8

./test21
Sending data to directory dir.ouT8S8

ls -al
total 72
drwxr-xr-x 3 rich rich 4096 Oct 17 22:20 ./
drwxr-xr-x 9 rich rich 4096 Oct 17 09:44 ../
drwx------ 2 rich rich 4096 Oct 17 22:20 dir.ouT8S8/
-rwxr--r-- 1 rich rich 338 Oct 17 22:20 test21*

cd dir.ouT8S8
ls -al
total 16
drwx------ 2 rich rich 4096 Oct 17 22:20 ./
drwxr-xr-x 3 rich rich 4096 Oct 17 22:20 ../
-rw------- 1 rich rich 44 Oct 17 22:20 temp.N5F3O6
-rw------- 1 rich rich 44 Oct 17 22:20 temp.SQslb7


cat temp.N5F3O6
This is a test line of data for temp.N5F3O6


cat temp.SQslb7
This is a test line of data for temp.SQslb7

这段脚本在当前目录创建了一个目录,然后它用cd命令进入该目录,并创建了两个临时文件。之后这两个临时文件被分配给文件描述符,用来存储脚本的输出。

记录消息

将输出同时发送到显示器和日志文件,这种做法有时候能够派上用场。你不用将输出重定向两次,只要用特殊的tee命令就行。

tee命令相当于管道的一个T型接头。它将从STDIN过来的数据同时发往两处。一处是STDOUT,另一处是tee命令行所指定的文件名

tee filename

由于tee会重定向来自STDIN的数据,你可以用它配合管道命令来重定向命令输出。

date | tee testfile
Sun Oct 19 18:56:21 EDT 2014

cat testfile
Sun Oct 19 18:56:21 EDT 2014

输出出现在了STDOUT中,同时也写入了指定的文件中。注意,默认情况下, tee命令会在每次使用时覆盖输出文件内容。

如果你想将数据追加到文件中,必须用-a选项。

利用这个方法,既能将数据保存在文件中,也能将数据显示在屏幕上。

#!/bin/bash
# using the tee command for logging
tempfile=test22file
echo "This is the start of the test" | tee $tempfile
echo "This is the second line of the test" | tee -a $tempfile
echo "This is the end of the test" | tee -a $tempfile



./test22
This is the start of the test
This is the second line of the test
This is the end of the test




cat test22file
This is the start of the test
This is the second line of the test
This is the end of the test
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值