14.2-在脚本中使用其他文件描述符
在脚本中重定向输入和输出,并布局限于以上讲的3个默认的文件描述符,shell最多可以有9个打开的文件描述符。这节介绍在脚本中使用其他文件描述符。
1.文件描述符的操作
Shell 中对文件描述符的操作由三部分组成: (Left, Operation, Right):
- Left 可以是 0-9 的数字, 代表第 n 号文件描述符;
Left 还可以为 &, 表示同时操作 stdout 和 stderr - Right 可以是文件名或 0-9 的数字, 当 Right 是数字时必须要加上 & 符号, 表示引用第 n 号文件描述符;
Right 还可以为 &-, 此时表示关闭 Left 描述符, 例如 2<&- 表示关闭 stderr; - Operation 可以为 < 或 >;
为 < 时表示以读模式复制 Right 到 Left, 此时如果没有指定 Left 的话, 则为默认值 0;
当为 > 表示以写模式复制 Right 到 Left, 此时如果没有指定 Left 的话, 则为默认值 1;
Operation 和 Left 之间不能有空格;
当 Right 为文件名时, Operation 和 Right 可以有空格, 否则也不能有空格;
当存在多个文件描述符的操作时, 会按照从左往右的顺序依次执行. 例如通过命令
1 cmd 3>&1 1>&2 2>&3 3>&-
就可以交换 stdin 和 stdout.
2 I/O重定向的常用用法
- command > filename 把标准输出重定向到一个新文件中
- command >> filename 把标准输出重定向到一个文件中(追加)
- command 1 > fielname 把标准输出重定向到一个文件中
- command > filename 2>&1 把标准输出和标准错误一起重定向到一个文件中
- command 2 > filename 把标准错误重定向到一个文件中
- command 2 >> filename 把标准输出重定向到一个文件中(追加)
- command >> filename 2>&1 把标准输出和标准错误一起重定向到一个文件中(追加)
- command < filename >filename2 把command命令以filename文件作为标准输入,以filename2文件作为标准输出
- command < filename 把command命令以filename文件作为标准输入
- command << delimiter 把从标准输入中读入,直至遇到delimiter分界符
- command <&m 把文件描述符m作为标准输入
- command >&m 把标准输出重定向到文件描述符m中
- command <&- 把关闭标准输入
- command %n%c file command 输出重定向的命令 ,%n 文件描述符,默认值为1,%c 重定向符 ,file 目标文件。
3. exec命令的介绍
exec命令用于调用并执行指令的命令。exec命令通常用在shell脚本程序中,可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端
exec用法:
- &n :代表描述符代表的文件
- > < :代表以什么形式使用描述符
- exec 8<&2 :描述符8以读取方式打开标准错误对应的文件
- exec &>log:把标准输入错误打开文件log
- exec 8<&- :关闭描述符8
4. 列出打开的文件描述符lsof
lsof会列出整个linux系统打开的所有文件描述符,,命令为隐藏状态。
很多的linux系统中(如Fedora),lsof命令位于/usr/sbin
1 lsof 2 command PID USER FD type DEVICE SIZE NODE NAME 3 init 1 root cwd DIR 8,2 4096 2 / 4 init 1 root rtd DIR 8,2 4096 2 / 5 init 1 root txt REG 8,2 43496 6121706 /sbin/init 6 init 1 root mem REG 8,2 143600 7823908 /lib64/ld-2.5.so 7 init 1 root mem REG 8,2 1722304 7823915 /lib64/libc-2.5.so 8 init 1 root mem REG 8,2 23360 7823919 /lib64/libdl-2.5.so 9 init 1 root mem REG 8,2 95464 7824116 /lib64/libselinux.so.1 10 init 1 root mem REG 8,2 247496 7823947 /lib64/libsepol.so.1 11 init 1 root 10u FIFO 0,17 1233 /dev/initctl 12 migration 2 root cwd DIR 8,2 4096 2 / 13 migration 2 root rtd DIR 8,2 4096 2 / 14 migration 2 root txt unknown /proc/2/exe 15 ksoftirqd 3 root cwd DIR 8,2 4096 2 / 16 ksoftirqd 3 root rtd DIR 8,2 4096 2 / 17 ksoftirqd 3 root txt unknown /proc/3/exe 18 migration 4 root cwd DIR 8,2 4096 2 / 19 migration 4 root rtd DIR 8,2 4096 2 / 20 migration 4 root txt unknown /proc/4/exe 21 ksoftirqd 5 root cwd DIR 8,2 4096 2 / 22 ksoftirqd 5 root rtd DIR 8,2 4096 2 / 23 ksoftirqd 5 root txt unknown /proc/5/exe 24 events/0 6 root cwd DIR 8,2 4096 2 / 25 events/0 6 root rtd DIR 8,2 4096 2 / 26 events/0 6 root txt unknown /proc/6/exe 27 events/1 7 root cwd DIR 8,2 4096 2 /
lsof输出各列信息的意义如下:
- COMMAND:进程的名称
- PID:进程标识符
- USER:进程所有者
- FD:文件描述符,应用程序通过文件描述符识别该文件
- TYPE:文件的类型,DIR表示字符型,BLK表示块型,DIR表示目录,REG表示常规文件
- DEVICE:设备的设备号
- SIZE:如果有的话,表示文件的大小
- NODE:本地文件的节点号
- NAME:文件名
一般在标准输出、标准错误、标准输入后还跟着文件状态模式:
- u:表示该文件被打开并处于读取/写入模式。
- r:表示该文件被打开并处于只读模式。
- w:表示该文件被打开并处于。
- 空格:表示该文件的状态模式为unknow,且没有锁定。
- -:表示该文件的状态模式为unknow,且被锁定。
同时在文件状态模式后面,还跟着相关的锁:
- N:for a Solaris NFS lock of unknown type;
- r:for read lock on part of the file;
- R:for a read lock on the entire file;
- w:for a write lock on part of the file;(文件的部分写锁)
- W:for a write lock on the entire file;(整个文件的写锁)
- u:for a read and write lock of any length;
- U:for a lock of unknown type;
- x:for an SCO OpenServer Xenix lock on part of the file;
- X:for an SCO OpenServer Xenix lock on the entire file;
- space:if there is no lock.
5. 记录消息tee
tee用于将数据重定向到文件,另一方面还可以提供一份重定向数据的副本作为后续命令的stdin。简单的说就是把数据重定向到给定文件和屏幕上。
- 默认情况下,tee命令在每次使用时候覆盖输出文件内容
- -a , 将数据追加到文件中
- -i ,忽略终端信号