您的位置:首页 > 其它

第4章 处理用户输入与显示数据------------(禁止命令输出、lsof命令、关闭文件描述符、创建读取/写入文件描述符)

2017-04-22 00:00 627 查看

4.5 创建自己的重定向

在脚本中重定向输入和输出时,并不局限于3中默认的文件描述符。在shell中最多可以有9个打开的文件描述符。其他6个文件描述符的编号从3~8。可以将这些文件描述符应用到任何文件,然后在脚本中使用它们。

4.5.1 创建输出文件描述符

使用exec命令为输出分配文件描述符。与标准的文件描述符一样,向文件位置分配备选文件描述符之后,该重定向将是永久性的,除非重新分配。

#!/bin/bash
#向文件位置分配备选文件描述符
exec 3>test3

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"




脚本使用exec命令将文件描述符3重定向到一个备选文件位置。当脚本执行echo语句时,它们将显示在STDOUT上,正如期望的那样,但是重定向到文件描述符3的echo语句定向到备选文件。这使用户能够将普通输出定向到监视器,将特殊信息重定向到文件。

4.5.2 重定向文件描述符

恢复重定向文件描述符的技巧:向标准文件描述符分配一个备选文件描述符,反之亦然。也就是说,可以将STDOUT的原位置重定向到备选文件描述符,然后将该文件描述符重定向回STDOUT

#!/bin/bash
#将STDOUT的原位置重定向到备选文件描述符
#然后将文件描述符充电向会STDOUT

#将文件描述符3重定向到文件描述符1的当前位置STDOUT
exec 3>&1
#将STDOUT重定向到一个文件
exec 1>test1

echo "This should store in the output file"
echo "along with this line"

#将文件描述符1重定向到文件描述符3
exec 1>&3
echo "Now things should be back to normal"




上述代码功能,类似变量之间的值相互交换。首先将文件描述符3重定向描述符1,执行完这一步之后:相当于描述符1和描述符3它们位置、功能调换了一下,之前描述符3所做的事由描述符1来做。

然后,exec命令将STDOUT重定向到一个文件。shell将任何直接发送到STDOUT的输出重定向到输出文件test1。文件描述符3指向STDOUT的位置,一旦有数据发送到描述符3,数据将出现在显示器上。

想描述符1发送一些输出后,将描述符1重定向到描述符3,也就是说,描述符1恢复到原有的功能,发送给描述符1的数据将显示在显示器上,描述符3任然设置为监视器。

4.5.3 创建输入文件描述符

可以使用重定向输入文件描述符的方式重定向输入文件描述符。在重定向到文件之前,将STDIN文件描述位置保存到另一个文件描述中,然后在完成了文件读取操作之后,将STDIN恢复为原来的位置。

#!/bin/bash
#使用重定向输出文件描述符的方式重定向输入文件描述符

#将STDIN文件描述符位置保存到另一个文件描述符
exec 6<&0

#读取文件信息
exec 0<test1
count=1
while read line
do
echo "Line #$count:$line"
count=$[ $count+1 ]
done

#将STDIN恢复为原来位置
exec 0<&6
read  -t 10 -p  "Are you done now?" answer
case $answer in
Y|y) echo "Goodbye,ewang!";;
N|n) echo "Sorry ,this is the end.";;
esac




使用文件描述符6保存STDIN位置,然后脚本将STDIN重定向到文件。read命令的所有输入都来自重定向后的STDIN,读取完所有行之后,脚本通过将STDIN重定向到文件描述6,将它设置会原来位置。脚本使用另一个read命令测试STDIN回到普通设置。

4.5.4 创建读取/写入文件描述符

可以为输入和输出打开同一个文件描述符。可以使用同一个文件描述符从一个文件读取数据,同时向这个文件写入数据。

当使用这种方法必须十分小心。读取文件和向该文件写入数据时,shell维护有一个内部指针,指示文件内部位置。读取和写入操作都发生在指针上次放置的地方。如果不小心,很容易出现错误:

#!/bin/bash
#创建读取/写入文件描符
exec 3<>test1
#读取test1文件的第一行
read line <&3
echo "Read :$line"
#向test1写入文件
echo "This is a test line" >&3




这样的操作容易造成,写入文件的数据覆盖现有的数据。造成这种问题原因:当脚本向文件写入数据时,它从文件指针所在的地方开始。read命令读取第一行数据后,文件指针指向第二行数据的第一字符。当echo语句输出到文件时,它将数据放在文件指针的当前位置,覆盖了此处的数据。

4.5.5 关闭文件描述符

如果创建新的输入或输出文件描述符,shell将在脚本退出时自动关闭它们。但有时需要在脚本结束前手动关闭文件描述符。要关闭文件描述符,将它重定向到特殊符号&-。具体操作实例如下所示:

#!/bin/bash
#关闭文件描述符:exec 描述符>&-
#创建一个输出文件描述符3
exec 3>test2

#向文件test2写入数据
echo "This is a test line of data" >&3

#关闭文件描述符3
exec 3>&-

#关闭描述符之后再向文件写入数据
#shell生成一个错误消息
echo "The 3 file descriptor has been closed!" >&3




关闭文件描述符之后,就不能在脚本中向它写入任何数据,否则shell将生成一个错误消息。关闭文件描述符时还需要注意:如果稍后在脚本中打开同一个输出文件,shell将使用新文件替换现有文件。这意味着如果输出任何数据,它将覆盖现有文件

#!/bin/bash
#关闭文件描述符:exec 描述符>&-
#判断当前目录下是否存在test开头的文件按
#如果存在删除该类文件
if [ -e "test1" ]
then
rm -rf test*
ls
fi
#创建一个输出文件描述符3
exec 3>test1

#向文件test2写入数据
echo "This is a test line of data" >&3

echo "显示当前test1文件内容"
cat test1
#关闭文件描述符3
exec 3>&-

#创建一个输出文件描述符3
exec 3>test1
#关闭描述符之后再向文件写入数据
#shell生成一个错误消息
echo "The 3 file descriptor has been closed!" >&3
echo "显示test1文件内容"
cat test1




将数据字符串发送到test1并且关闭文件描述符之后,脚本使用cat命令显示文件的内容。到目前为止没有问题,接下来,脚本重新打开输出文件并向其发送另一个数据字符串。当显示内容时,看到的所有内容只有第二个字符串。shell覆盖了原来的输出文件。

4.5.6列出开发文件描述符

lsof命令列出整个linux系统上所有的开发文件描述符。这是一项具有争议的功能,因为它向非系统管理员提供有关Linux系统信息。因此,许多Linux系统都隐藏了该命令,以防用户无意中使用它。在Ubuntu14.1系统中,可以直接使用lsof命令。执行该命令时,它显示Linux系统上当前开放的每个文件的相关信息,包括后台运行的进程,以及所有登录到系统的用户账户。



上图是lsof命令参数解释说明。最常用的是-p,该参数可以指定进程ID(PID),还有-d,该参数可以指定要显示的文件描述符编号。使用$$特殊环境变量,可以轻松的确定进程的当前PID。-a选项可以用来连接其他两个选项的结果。操作实例:



lsof的默认输出信息列如下:



与STDIN、STDOUT、STDERR关联的文件类型是字符模式。由于STDIN、STDOUT、STDERR文件描述符都指向终端,则输出文件的名称时终端的设备名。所有3个标准文件都可以用于读取和写入。从打开几个备选文件描述符的脚本内部查看lsof命令结果。

#!/bin/bash
#使用lsof命令
exec 3>test3
exec 6>test6
exec 9>test9

lsof -a -p $$ -d 1,2,3,6,9




该脚本创建了3个备选文件描述符(3,6,9),三个文件都用于输出,当脚本运行lsof命令时,可以看到输出中的新文件描述符。文件名显示文件在文件描述符中使用的完整路径名。显示每个文件的类型是REG,表示它们是文件系统的常规文件。

4.5.7禁止命令输出

有时候不希望显示任何脚本输出信息,要解决这个问题,可以重定向到称为空文件的特殊文件。该文件不包含任何内容。shell输出到空文件的任何数据都不会保存,即全部丢失。该文件在liunx系统的标准位置是/dev/null任何重定向到该位置的数据都丢失且不会显示。

这是一种常见的禁止错误消息而不保存的方法。可以使用/dev/null文件作为输入文件用于重定向。因为/dev/null文件不包含任何内容,程序员进程使用它快速将数据从现有文件移除,无需移除文件并重新创建它。这是一种常见的清除日志文件的方法

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐