碎片时间x体系学习
这是第145篇原创;距2019年还有168天
00
Shell的人机输出交互
通过前面的文章,我们知道有两种显示脚本输出的方法:
屏幕显示内容输出
内容输出重定向到文件中
这两种方法要么将全部内容显示在屏幕上,要么将全部内容重定向到文件中。但是,在一些场合我们希望在显示器上显示部分数据,而部分数据保存到文件中。以下我们将讨论一些高级的shell输出方法,实现将脚本输出重定向到特定位置。
01
文件描述符
Linux系统中将每个对象都当做文件来处理,并用文件描述符来标识每个文件对象;文件描述符用一个非负整数进行唯一标识;bash shell保留了最前面的3个文件描述符:
0:STDIN,标准输入
1:STDOUT,标准输出
2:STDERR,标准错误
1.1 STDIN
STDIN文件描述符代表shell的标准输入。对终端界面而言,标准输入是键盘;shell从STDIN文件描述符对应的键盘获得输入。
在使用输入重定向符号(
1.2 STDOUT
STDOUT文件描述符代表shell的标准输出。对终端界面而言,标准输出是显示器;shell的所有输出会被定向到标准输出上。
通过输出重定向符号(>),通常会将显示到显示器的所有输出会被shell重定向到指定的重定向文件中;当然,我们也可以用>>符号,实现将数据追加到文件中。
注意:当命令生成错误信息时,shell并不会将错误消息重定向到输出重定向文件中,而是直接输出到了控制台;这是因为shell处理错误消息和处理普通输出是分开的。
1.3 STDERR
STDERR文件描述符用于处理错误消息,shell输出的错误信息都会发送到该位置。默认情况下,标准输出信息与标准错误输出信息都会将输出信息发送到控制台终端;从上面分析得知,重定向STDOUT并不会自动重定向STDERR。
02
重定向错误
在重定向错误时,一般有两种业务需求:
只重定向错误
同时重定向错误和数据
2.1 只重定向错误
STDERR文件描述符被设定为2,如果选择只重定向错误信息,可以将该文件描述符值放在重定向符号前,并且该值必须紧贴在重定向符号前,否则不会正常工作。如下例所示,我们罗列了一个Hello.sh文件以及一个根本就不存在的文件friendfb,可以发现标准的输出消息显示在了控制台,而将系统报出的错误信息重定向到log.1文件。
2.2 同时重定向错误和数据
在上例中,我们利用“2>”实现了只重定向标准错误信息;如果我们要同时重定向错误和数据,以下提供两种方法实现不同的功能。
方法1:利用两个重定向符号,2>与1>。
方法2:利用&>重定向符号,可以实现将错误与数据重定向到一个文件中,如下例。
03
重定向输出
我们可以在脚本中利用STDOUT和STDERR文件描述符在多个位置生成输出,只要简单地重定向相应的文件描述符即可。有两种方法实现该功能:
临时重定向每行输出
永久重定向脚本中的所有命令
3.1 临时重定向每行输出
以错误消息为例。在某些业务场景下,我们需要将特定命令的错误输出信息或自定义的错误信息输出到文件中,那么我们需要使用输出重定向符将输出重定向到STDERR文件描述符。在重定向到文件描述符时,我们需要在文件描述符数字之前加一个&。
在上例中,我们实现了对特定错误消息的定向输出。这个方法非常适合在脚本中生成错误信息。
3.2 永久重定向
如果脚本中有大量的信息需要重定向,采用上述的方法需要对每个消息进行重定向,显然是不可取的。Linux系统提供了exec命令,可以实现在脚本执行期间重定向某个特定文件描述符。
上述方法可普遍应用于读取文件内容,如读取、分析日志文件等应用场景中。
04
重定向输入
我们可以用在脚本中重定向STDOUT和STDERR的同样方法将STDIN从键盘重定向到其他位置;同样也可采用exec命令实现将STDIN重定向到Linux系统上的文件中。
05
自定义重定向
在脚本中重定向输入输出时,并不局限于这3个默认的文件描述符。在Shell中最多可以有9个打开的文件描述符,其余的6个文件描述符为从3-8,这些即可当做输入重定向,也可当做输出重定向。你可以将这些文件描述符中的任意一个分配给文件,然后在脚本中使用它们。示例如下:
在上例中,首先是第一个exce命令将文件描述符3(自定义的重定向描述符)重定向到文件描述1(STDOUT),这样任何发送给3的输出都会出现在显示器上;第二个exec命令是将显示器上的内容重定向到log.out文件中;第三个exec命令则是将STDOUT重定向到3,也就是再次回到了显示器,通过该方法我们也就恢复了重定向。
如上所示,当我们创建了新的输入或输出文件描述符,shell会在脚本退出时自动关闭它们。然而在特定场景下,我们需要在脚本结束前主动关闭文件描述符。要关闭文件描述符,将它重定向到特殊符号&-,如下所示,我们手动关闭了文件描述符3:
在某些场景下,我们需要知道有哪些文件描述符被重定向到了哪里,Linux系统为我们提供了lsof命令;该命令会列出整个Linux系统打开的所有文件描述符。如下列所示:
在上例中,我们自定义了文件描述符3、4、5;然后又关闭了3;最后我们调用lsof命令去查看文件描述符0-5分别被重定向到的文件,从结果中可以看到0、1、2、4、5的重定向情况,而无法查看已经关闭了的描述符3的情况。
06
一些重要命令
6.1 阻止命令输出
在脚本作为后台运行等场景下,我们并并希望显示脚本的任何输出;Linux为我们提供了一个“无底洞”——/dev/null文件,凡是内容进入该文件,都会被“吞噬”,消失的无影无踪。
格式:command > /dev/null
执行上述命令,commad的任何消息输出都会被丢弃掉。
6.2 显示+记录消息
有时我们需要将脚本的输出一边显示在控制台,也希望一边能发送到日志文件;Linux为我们提供了tee命令可以实现上述业务场景的需要。
格式1:command | tee fileName
格式2:command | tee -a fileName
执行格式1的命令,commad消息输出既可以显示在控制台也可以记录在fileName文件中;格式2的命令增加了“-a”选项,主要用于将输出的消息可以追加到fileName文件中。
6.3 创建临时文件
Linux为我们提供了/tmp目录用于存放不需要一直保留的文件,因为每次Linux启动的时候都会自动删除/tmp目录下的所有文件。系统上的任何用户都有权限在/tmp目录中读和写。这个特性为我们提供了简单地创建临时文件的途径,而不用管理清理工作。
Linux系统提供了mktemp命令用于创建临时文件或目录。
格式1:mktemp fileName
在/tmp目录下创建临时文件,返回文件名。
格式2:mktemp -t fileName
在/tmp目录下创建临时文件,返回临时文件的全路径。
格式3:mktemp -d fileName
在/tmp目录下创建临时目录,返回目录名。
07
小结
综上,本文对shell的内容输出进行了介绍。
脚本的输入可以从标准输入(STDIN)重定向到系统上的任意文件上;可以从标准输出(STDOUT)重定向到系统上的任意文件;可以从标准错误输出(STDERR)重定向到系统上的任意文件;可以将STDERR输出和STDOUT输出到同一个文件中,也可以分别输出到不同的文件中,这样便于实现正常的脚本消息和错误信息分离存放。此外,bash shell运行在脚本中创建自己的文件描述符,并可利用标准的重定向符号将任意命令的输出内容进行重定向。
Linux提供了一个特殊文件/dev/null来重定向不需要的输出,Linux会删除任何重定向到 /dev/null文件的东西,可以理解该文件是Linux系统中的“无底洞”。
mktemp命令可以在Linux系统的/tmp目录下创建唯一的临时文件和目录,当Linux系统重启时会情况/tmp下的文件、目录内容。
tee命令实现了将输出内容同时发送给标准输出和日志文件,也就是说既可以在显示器上显示脚本的消息,又能同时把输出内容保存在日志文件中。
在下文中,我们将会对脚本的运行控制技术进行介绍。敬请期待!
One More Thing
推荐1:硬技术与软技能干货分享
上文1:Linux#8 Shell的人机交互 - 输入篇
上文2:Linux#7 shell结构化循环命令进阶
近期,我和活跃在业界的一线技术老司机们共同开通了知识星球,——一个与公众号有别,但又一脉相承的技术圈、认知圈:公众号会一如既往地进行知识分享,知识星球则坚持关注解决问题与动手实践,主要涉及Java后端、Linux、Python、Android等技术领域,问题很广、方法很多、思绪很快,希望我们能够在这里驻足思考、交流、沉淀、提升。
你负责认真,我们负责帮你解决问题,让改变发生;欢迎大家扫码加入我们的星球。期待 2018,在程序猿成长的道路上,共同进化!
领取专属 10元无门槛券
私享最新 技术干货