一个有意思的问题
问题描述
1 | $mysql -N -h127.0.0.1 -e "select id from sbtest1 limit 1" |
如上第一和第二个语句,为什么mysql client的输出重定向后就没有ascii制表符了呢?
语句三加上 -t后再经过管道,也有制表符了。
stackoverflow上也有很多人有同样的疑问,不过不但没有给出第三行的解法,更没有人讲清楚这个里面的原理。所以接下来我们来分析下这是为什么
-N 去掉表头
-B batch 模式,用tab键替换分隔符
分析
strace看看第一个语句:
再对比下第二个语句的strace:
从上面两个strace比较来看,似乎mysql client能检测到要输出到命名管道(S_IFIFO )还是character device(S_IFCHR),如果是命名管道的话就不要输出制表符了,如果是character device那么就输出ascii制表符。
1 | printf("File type: "); |
第4行和第6行两个类型就是导致mysql client选择了不同的输出内容
误解
所以这个问题不是:
为什么mysql client的输出重定向后就没有ascii制表符了呢?
而是:
mysql client 可以检测到不同的输出目标然后输出不同的内容吗? 管道或者重定向是一个应用能感知的输出目标吗?
误解:觉得管道写在后面,mysql client不应该知道后面是管道,mysql client输出内容到stdout,然后os将stdout的内容重定向给管道。
实际上mysql是可以检测(detect)输出目标的,如果是管道类的非交互输出那么没必要徒增一些制表符;如果是交互式界面那么就输出一些制表符好看一些。
要是想想在Unix下一切皆文件就更好理解了,输出到管道这个管道也是个文件,所以mysql client是可以感知各种输出文件的属性的。
背后的实现大概是这样:
1 | #include <stdio.h> |
结论就是 mysql client根据输出目标的不同(stdout、重定向)输出不同的内容,不过这种做法对用户体感上不是太好。
其它
Linux管道居然不是按顺序,而是并发执行的:https://unix.stackexchange.com/questions/37508/in-what-order-do-piped-commands-run 掉坑里了,并发问题就多了,实际测试也发现跑几千次 ps |grep 会出现,ps看不到后面的grep进程
参考资料
https://www.oreilly.com/library/view/mysql-cookbook/0596001452/ch01s22.html