linux系统的数据呈现

一、理解输入和输出

脚本的输出显示可以显示在显示器屏幕上也可以重定向到文件中。这两种方法要么将数据输出全部显示,要么什么都不显示。但有时将一部分数据在显示器上显示,另一部分数据保存到文件中也是不错的。下面就会介绍如何使用标准的linux输入和输出系统将脚本输出导向特定位置。

(1)标准文件描述符

linux系统将每个对象当作文件处理。这包括输入和输出进程。linux用文件描述符来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有9个文件描述符。出于特殊目的,bash shell保留了前三个文件描述符(0,1,2)。

linux的标准文件描述符
文件描述符缩写描述
0STDIN标准输入
1STDOUT标准输出
2STDERR标准错误

STDIN文件描述符代表shell的标准输入,对终端界面来说,标准输入就是键盘。

STDOUT文件描述符代表shell的标准输出,在终端界面上,标准输出就是显示器。

STRERR文件描述符处理错误消息,代表shell的标准错误输出。shell或者shell中运行的程序或者脚本出错时生成的错误信息都会发送到这个位置。默认情况下,STDERR和STDOUT指向同样的地方,即错误消息也会输出到显示器。

(2)重定向错误

(2.1)只重定向错误

选择只重定向错误消息,将文件描述符值放在重定向符号前即可。文件描述符值必须紧紧地放在重定向符号前,否则不会工作。

案例:
ls 一个没有的文件,将错误消息重定向到文件test
[root@locahost]# ls -al test.txt 2> test
[root@locahost]# cat test
ls: cannot access test.txt: No such file or directory

(2.2)重定向错误和数据

如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件。

案例:将ls命令的正常输出重定向到test1文件,错误消息重定向到test3文件。
ls -al test.txt test1 2> test2 1> test3

如果想要把STDERR和STDOUT的输出重定向到同一个输出文件,可以使用特殊的重定向符号(&>)。

ls -al test.txt test1 &> test

上面的案例使用了&>符号,会把ls命令的所有输出都发送到同一位置,包括数据和错误。

二、在脚本中重定向输出

有两种方法在脚本中重定向输出:第一,临时重定向行输出;第二,永久重定向脚本中的所有命令。

(1)临时重定向 

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

cat test.sh
#!/bin/bash
echo "this is an error" >&2
echo "this is normal output"

如果直接运行脚本test.sh,可能看不出什么区别。
[root@~]# ./test.sh
this is an error
this is normal output

默认情况下,linux会将STDERR导向STROUT。但是,如果你在运行脚本时重定向了STDERR,脚本中所有导向STDERR的文本都会被重定向。
[root@~]# ./test.sh 2> test
this is normal output
[root@~]# cat test
this is an error

可以看出通过STDOUT显示的文本显示在了屏幕上,发送给STDERR的echo语句的文本被重定向到了test输出文件中。这个方法非常适合在脚本中生成错误消息。

(2)永久重定向

如果脚本中有大量数据需要重定向,那重定向每个echo语句会非常繁琐,我们可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。

cat test.sh
#!/bin/bash
exec 1>test

echo "this is a test"
echo "this is a test output"

脚本执行的输出结果:
[root@~]# sh test.sh
[root@~]# cat test
this is a test
this is a test output

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

三、在脚本中重定向输入

exec命令允许将STDIN重定向到linux系统上的文件中:

exec 0< testfile

这个命令会告诉shell它应该从文件testfile中获得输入,而不是STDIN。这个重定向只要在脚本需要输入时就会起作用。

cat test.sh
#!/bin/bash
exec 0< testfile
count=1
while read line
do
  echo "Line #$count:$line"
  count=$[ $count+1 ]
done

testfile文件的内容如下:
this is the first line.
this is the second line.
this is the third line.

脚本的执行结果:
[root@~]# ./test.sh
Line #1:this is the first line.
Line #2:this is the second line.
Line #3:this is the third line.

四、创建自己的重定向

(1)创建输出文件描述符

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

cat test.sh
#!/bin/bash
exec 3> testout

echo "this is a test"
echo "this should be stored in the file" >&3
echo "this should stored on the monitor"

脚本执行结果
[root@~]# sh test.sh
this is a test
this should stored on the monitor
[root@~]# cat testout
this should be stored in the file

这个脚本中用exec命令将文件描述符3重定向到另一个文件testout。当脚本执行echo语句时,输出内容会像预想中那样显示在STDOUT,但重定向到文件描述符3的echo语句的输出会进入另一个文件。

五、重定向文件描述符

可以分配另外一个文件描述符给标准文件描述符,反之亦然。这意味着可以将STDOUT的原来位置重定向到另一个文件描述符,然后在利用该文件描述符重定向回STDOUT。

cat test.sh
#!/bin/bash

exec 3>&1
exec 1> testout

echo "this is a test"

exec 1>&3

echo "this is a another test"

上述脚本执行结果如下:

[root@~]# chmod u+x test.sh
[root@~]# ./test.sh
this is a another test
[root@~]# ll
total 8
-rw-r--r-- 1 root root       15 Feb  9 13:44 testout
-rwxr--r-- 1 root root      104 Feb  9 13:44 test.sh
[root@~]# cat testout
this is a test

脚本中首先将文件描述符3重定向到文件描述符1的当前位置,也就是STDOUT。这意味着任何发送给文件描述符3的输出都将会出现在显示器上。第二个exec命令将STDOUT重定向到文件testout。shell现在会将发送给STDOUT的输出直接重定向到输出我呢见testout中。但是文件描述符3仍然指向STDOUT原来的位置,即显示器。如果此时将输出数据发送给文件描述符3,他仍然会显示在显示器上。尽管STDOUT已经被重定向了。在向STDOUT发送一些输出之后,脚本将STDOUT重定向到文件描述符3,即显示器。这意味着STDOUT指向了原来的位置,显示器。

(2)创建输入文件描述符

在重定向到文件之前,先将STDIN文件描述符保存到另一个文件描述符,然后在读取完文件之后再将STDIN恢复他原来的位置。

cat test.sh
#!/bin/bash
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 "Good Bye";;
N|n) echo "Sorry";;
esac

执行结果如下:

[root@~]# ./test.sh
Line #1:this is the first line.
Line #2:this is the second line.
are you done now? y
Good Bye

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

(3)关闭文件描述符

如果你创建了新的输入或输出文件描述符,shell会在脚本退出时自动关闭它们。在某些情况先,需要在脚本结束前手动关闭。要关闭文件描述符,将它重定向到特殊符号&-。

比如关闭文件描述符3,可以使用下面的命令

exec 3>&-

六、记录消息

将输出同时发送到显示器和日志文件,不需要重定向2此,只要使用命令tee即可。

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

tee filename

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

[root@~]# date|tee testfile
Sun Feb  9 14:11:10 CST 2020
[root@~]# cat testfile
Sun Feb  9 14:11:10 CST 2020

默认情况下,tee命令会在每次使用时覆盖输出文件内容。如果想追加到文件中,可以使用-a选项。

[root@~]# who |tee -a testfile
root     pts/0        2020-02-03 12:12 (10.12.28.29)
[root@~]# cat testfile
Sun Feb  9 14:11:10 CST 2020
root     pts/0        2020-02-03 12:12 (10.12.28.29)

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

七、知识点补充

脚本中经常会有这样的用法,>/dev/null 2>&1。这条命令其实分为两命令,一个是>/dev/null,另一个是2>&1

>/dev/null

这条命令的作用是将标准输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。

2>&1

这条命令的作用是错误输出将和标准输出同用一个文件描述符,说人话就是错误输出将会和标准输出输出到同一个地方。

linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的作用就是让标准输出重定向到/dev/null中(丢弃标准输出),然后错误输出由于重用了标准输出的描述符,所以错误输出也被定向到了/dev/null中,错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。

>/dev/null 2>&1 VS 2>&1 >/dev/null

乍眼看这两条命令貌似是等同的,但其实大为不同。刚才提到了,linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令。那么我们同样从左到右地来分析2>&1 >/dev/null

2>&1,将错误输出绑定到标准输出上。由于此时的标准输出是默认值,也就是输出到屏幕,所以错误输出会输出到屏幕。
>/dev/null,将标准输出1重定向到/dev/null中。

我们用一个表格来更好地说明这两条命令的区别:

命令标准输出错误输出
>/dev/null 2>&1丢弃丢弃
2>&1 >/dev/null丢弃屏幕
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

#慧#

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

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

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

打赏作者

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

抵扣说明:

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

余额充值