linux重定向

1 重定向基础

# >output
# ls /bin/ls /file_not_exist >>output 2>&1
# ls /bin/ls /file_not_exist >>output 2>&1
# ls /bin/ls /file_not_exist &>>output
# cat output
ls: cannot access /file_not_exist: No such file or directory
/bin/ls
ls: cannot access /file_not_exist: No such file or directory
/bin/ls
ls: cannot access /file_not_exist: No such file or directory
/bin/ls
# ls /bin/ls /file_not_exist >>output 2>>&1
sh: syntax error near unexpected token `&'

第1行重定向,因为没有任何命令,相当于清空了output的内容。

第2,3,4行是等价的,标准输出以追加方式重定向到output,错误输出(用2表示)重定向到了标准输出(用1表示),这个从output的内容可以看出。也可以用第4行的形式,把标准输出和错误输出重定向到同一个文件。

重定向是 > ,默认是覆盖写,如果想要追加,使用 >> 。 这里很容易被误导,认为有 2>&12>>&1 两种形式,事实上只有第一种,如果标准输出是覆盖写,那么错误输出也是覆盖写,如果标准输出是追加写,那么错误输出也是追加写。最后一个命令报错,就是这个原因,不存在 2>>&1

2 程序对重定向的感知

# ls /etc/default/
cassandra  influxdb  jetty  nss  useradd
# ls /etc/default/ > output
# cat output
cassandra
influxdb
jetty
nss
useradd
# ls /etc/default/ | wc -l
5

按通常的理解,重定向只是把本来要输出到屏幕(标准输出)的内容输出到文件而已,两者内容应该是一样的。这并不总是正确。例如ls输出到屏幕和输出到文件、输出到管道是不同的。

这是ls实现很优雅的地方,它有办法感知输出的地方是屏幕还是其它。对比下面strace的输出,看出ls用 ioctl 探测了标准输出是不是屏幕。

# strace -e trace=ioctl -f bash -c 'ls /etc/default'
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=41, ws_col=164, ws_xpixel=1476, ws_ypixel=779}) = 0
cassandra  influxdb  jetty  nss  useradd
# strace -e trace=ioctl -f bash -c 'ls /etc/default > output'
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff836902c0) = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(1, TIOCGWINSZ, 0x7fff83690420) = -1 ENOTTY (Inappropriate ioctl for device)

ls命令的输出是有高亮的(区分文件,目录,符号链接等),高亮是通过输出不可见字符实现的,如果不能感知是否重定向,那么不可见字符就会输出到文件中,当我们在shell脚本中使用 FILES=$(ls /etc/default/) (这里隐含了重定向)得到就是混杂着不可见字符的文件名。

理解了这些,你的命令习惯会有微妙的变化。例如 ls /etc/default | wc -l 获取目录下有多少文件,而不用担心像屏幕输出一样,一行有多个文件,导致计数错误。

通过感知输出,可以让屏幕输出方便肉眼看,而重定向的数据方便程序处理,看mysql的例子,重定向得到的输出非常利于程序处理。

# mysql -u root -S /search/mysql3306/mysql.sock -e 'show databases'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
+--------------------+
# mysql -u root -S /search/mysql3306/mysql.sock -e 'show databases' | cat
Database
information_schema
test

不得不感慨,这些程序之优雅,*NIX气息之浓郁。当你碰到命令输出不方便程序处理时,不妨看看它重定向后的内容是什么样子的。

Author: root

Created: 2016-10-19 三 12:31

Validate