接上一篇文章shell编程(八) : [shell基础] 处理用户输入
- 3.4 呈现数据
- 3.4.1 关于输入和输出
- 3.4.2 重定向标准错误
- 1.只重定向标准错误
- 2.同时重定向标准错误和标准输出
- 3.4.3 在脚本中使用重定向
- 1. 临时重定向
- 2. 永久重定向
- 3.4.4 创建自己的重定向
- 3.4.5 列出打开的文件描述符
- 3.4.5 阻止命令输出
- 3.4.6 创建临时文件/目录
- 3.4.7 记录消息(日志)
有时我们需要将脚本的输出重定向到屏幕或文件来展示相关的信息,接下来介绍怎么实现这一功能。
3.4.1 关于输入和输出在Linux中有一个理念“一切皆文件”,包括进程的输入输出,进程的输入输出操作文件就是文件描述符,如下:
| 文件描述符 | 缩写 | 描述 |
|---|---|---|
| 0 | STDIN | 标准输入 |
| 1 | STDOUT | 标准输出 |
| 2 | STDERR | 标准错误 |
这三个特殊文件描述符会处理脚本的输入和输出。shell用它们将shell默认的输入和输出导向到相应的位置。
3.4.2 重定向标准错误前面介绍过重定向输出和重定向输入,对于标准错误,可以用同样的方法。由于错误也属于输出,所以重定向错误也使用 >符号。以前我们用 >符号其实包含了缺省值,即 1> ,代表重定向标准输出,如果要指定重定向标准错误,就要使用 2>。
标准输出和标准错误可以单独重定向也可以同时重定向。
1.只重定向标准错误重定向标准错误前,输出错误和命令行的打印内容,重定向标准错误后,只有命令行的打印内容,错误被重定向写入了 test 文件。
2.同时重定向标准错误和标准输出将标准输出重定向到了文件 test1,将标准错误重定向到了文件 test2,可以用这种方法将脚本的正常输出和脚本生成的错误消息分离开来,以便于有针对性的存储。
也可以将标准错误和标准输出重定向到同一个文件,但不是使用 1> test 2> test ,bash shell提供了另一个重定向符号 &>
3.4.3 在脚本中使用重定向可以在脚本中用 STDOUT 和 STDERR 文件描述符以在多个位置生成输出,只要简单地重定向相应的文件描述符就行了。重定向输出同理。
有两种方法来在脚本中重定向输出:
- 临时重定向行输出
- 永久重定向脚本中的所有命令
但我们的脚本想要利用 Linux 的文件描述符输出错误信息时,可以将我们要输出的内容重定向到 STDERR文件描述符,如下:
看起来和普通输出一样,这是因为这就是普通输出,哈哈,因为默认情况下,Linux 会将 STDERR 导向 STDOUT 中,所以,这里的输出其实就是标准输出。
怎样才能看出他们的区别呢?我们将 STDERR 重定向,
可以看到,执行脚本时只输出了 STDOUT 的内容,STDERR 则被重定向到 stderr.log 中。
2. 永久重定向如果脚本中有大量数据需要重定向,重定向每个 echo 语句就会很烦琐。可以用 exec 命令告诉shell在脚本执行期间重定向某个特定文件描述符。
其中,exec 2>testerror 将 STDERR 重定向到 testerror 文件。exec 1>testout 将 STDOUT 重定向到 testout 文件。
3.4.4 创建自己的重定向除了 0、1、2 三个文件描述符,还有另外6个文件描述符 3-8,可以自定义这些文件描述符,如下:
#!/bin/bash # 自定义文件描述符,并重定向 exec 3>test3out # 使用文件描述符 echo "This should be stored in the file." >&3
利用自己创建的文件描述符恢复 STDOUT、STDERR 的重定向:
#!/bin/bash # 利用自建文件描述符备份STDOUT文件描述符 exec 3>&1 exec 1>test14out echo "This should store in the output file." exec 1>&3 echo "Now things should be back to normal."
对于文件读写,也可以使用自建文件描述符,不过要注意文件内部指针的位置:
执行脚本后 testfile 的内容丢失了一部分,这是因为读取第一行后,文件内部指针位于第二行行首,紧接着就写入了内容,把原有的内容覆盖了。
关闭文件描述符,结束对文件的操作后,要将文件描述符重定向到特殊符号 &- 即关闭文件描述符。
关闭文件后,再使用文件描述符操作文件就会报错。
3.4.5 列出打开的文件描述符有时打开的文件描述符过多,需要列出它们,linux提供了 lsof 命令实现这一功能。
lsof 命令会列出整个Linux系统打开的所有文件描述符。因为它会向非系统管理员用户提供Linux系统的信息,所以许多Linux系统隐藏了该命令,没有加到全局环境中。如果想使用它,需要使用绝对路径,一般它位于 /usr/sbin/lsof 。
由于lsof会显示当前Linux系统上打开的每个文件的有关信息,打印信息较多,需要过滤,所以 lsof 有许多参数选项,常用的有 :
| 参数选项 | 描述 |
|---|---|
| -p PID | 指定进程ID(PID) |
| -d 文件描述符 | 指定要显示的文件描述符编号 |
| -a | 对其他选项的结果执行布尔AND运算 |
其中,$$是特殊的环境变量,存储当前进程的ID(PID)。
lsof 的各输出字段意义:
| 列字段 | 描述 |
|---|---|
| COMMAND | 正在运行的命令名的前9个字符 |
| PID | 进程的PID |
| USER | 进程属主的登录名 |
| FD | 文件描述符号以及访问类型(r代表读,w代表写,u代表读写) |
| TYPE | 文件的类型(CHR代表字符型,BLK代表块型,DIR代表目录,REG代表常规文件) |
| DEVICE | 设备的设备号(主设备号和从设备号) |
| SIZE/OFF | 以字节为单位的文件大小或文件偏移量。 以“0t”或“0x”开头的数据代表偏移量。 |
| NODE | 本地文件的节点号 |
| NAME | 文件名 |
在脚本中使用 lsof
3.4.5 阻止命令输出有时不需要命令行输出内容,比如需要脚本在后台运行时。
这时可以将命令的输出重定向到 null 文件,它是一个特殊文件,里面什么也没有,即使写入了数据也会被系统丢掉。在Linux系统中,null 文件的标准路径是 /dev/null。
同样,可以将数据重定向到null,也可以将null的内容重定向到文件,即清空文件。
3.4.6 创建临时文件/目录有时我们需要创建临时文件存放不需要永久保留的数据,linux为我们提供了mktemp命令和存放临时文件的目录/tmp。
系统上的任何用户账户都有权限在读写/tmp目录中的文件。
使用 mktemp 命令创建本地临时文件:
# 首先创建模板,文件名自定义,扩展名为6个大写的X # 系统会使用数字和大小写字母在6个X的位置随机填充,且会保证文件名的唯一性 mktemp testtemp.XXXXXX
mktemp 命令的输出是创建的文件的名字。在脚本中使用mktemp命令时,可以将文件名保存到变量中,然后在后面做处理。
在系统的 tmp 目录创建临时文件也可以使用 mktemp 命令,只不过要使用-t选项:
mktemp -t testtemp.XXXXXX
这时命令返回的是临时文件的绝对路径。
使用 mktemp 的 -d 选项可以创建临时目录,目录名同样符合上面的规则:
mktemp -d testtemp.XXXXXX
大概你已经想到,同时使用 -t 和 -d 选项可以在 /tmp 目录下创建临时目录。
3.4.7 记录消息(日志)如果希望消息即在屏幕显示,也要写入文件中,使用上面的重定向方法需要重定向两次,为了不必要的麻烦,linux提供了 tee 命令。
它可以将 STDIN 的数据同时发送到 STDOUT 和 指定文件中,命令格式如下:
tee filename
hello 即在屏幕显示了,也写入了 tee.log 文件。
注意,tee 命令默认情况下每次写入是覆盖模式,如果想使用追加模式,需要加 -a 选项,如下:
文件的初始内容为 hello ,第一次写入hi 将 hello 覆盖了,第二次使用 -a 选项,写入 hello ,是追加在 hi 的后面。


![shell编程(九) : [shell基础] 呈现数据 shell编程(九) : [shell基础] 呈现数据](http://www.mshxw.com/aiimages/31/887050.png)
