第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文件不包含任何内容,程序员进程使用它快速将数据从现有文件移除,无需移除文件并重新创建它。这是一种常见的清除日志文件的方法。
相关文章推荐
- 第4章 处理用户输入与显示数据------------(禁止命令输出、lsof命令、关闭文件描述符、创建读取/写入文件描述符)
- 第4章 处理用户输入与显示数据------------(禁止命令输出、lsof命令、关闭文件描述符、创建读取/写入文件描述符)
- 第4章 处理用户输入与显示数据------------(创建本地临时文件、在/temp中创建临时文件、创建临时目录、tee命令)
- 第4章 处理用户输入与显示数据------------(创建本地临时文件、在/temp中创建临时文件、创建临时目录、tee命令)
- 第4章 处理用户输入与显示数据------------(创建本地临时文件、在/temp中创建临时文件、创建临时目录、tee命令)
- 第4章 处理用户输入与显示数据------------(getopt命令)
- 第4章 处理用户输入与显示数据------------(从键盘输入的命令read,对输入计时计数)
- 第4章 处理用户输入与显示数据------------(更高级的getopts命令、标准化选项)
- 第4章 处理用户输入与显示数据------------(标准文件描述符、STDIN/STDERR/STDOUT、临时重定向、永久重定向exec)
- 第4章 处理用户输入与显示数据------------(标准文件描述符、STDIN/STDERR/STDOUT、临时重定向、永久重定向exec)
- 第4章 处理用户输入与显示数据------------(从键盘输入的命令read,对输入计时计数)
- 第4章 处理用户输入与显示数据------------(标准文件描述符、STDIN/STDERR/STDOUT、临时重定向、永久重定向exec)
- 第4章 处理用户输入与显示数据------------(更高级的getopts命令、标准化选项)
- 第4章 处理用户输入与显示数据------------(getopt命令)
- 第4章 处理用户输入与显示数据------------(默读与文件读取)
- 第4章 处理用户输入与显示数据------------(更高级的getopts命令、标准化选项)
- 第4章 处理用户输入与显示数据------------(默读与文件读取)
- 第4章 处理用户输入与显示数据------------(getopt命令)
- 第4章 处理用户输入与显示数据------------(默读与文件读取)
- 第4章 处理用户输入与显示数据------------(读取参数、读取程序名称、测试参数)