你有没有留意过下面这种场景:git
$ lsshell file1 file2 file3 file4 file5小程序 $ ls | cat函数 file1spa file2ip file3it file4io file5table |
单独执行 ls 时,它的输出是一行多个文件名,在它后面接个管道的话,它的输出就变成了一行一个文件名,这是为何呢?这种表现的原理是:ls 程序自身能够判断出(经过 isatty() 库函数)它的标准输出是指向了一个终端,仍是别的什么地方(管道或者普通文件)。若是是前者,则按一行多个文件名输出,不然按一行一个输出。class
咱们能够本身写个简单的 c 程序演示一下:
$ cat foo.c #include <stdio.h> int main() { printf(isatty(1) ? "终端\n" : "非终端\n"); } $ gcc foo.c -o foo $ ./foo 终端 $ ./foo | cat 非终端 $ ./foo > file $ cat file 非终端 |
然而恰恰有时候,在咱们想要把一个命令的标准输出保存起来或者交给其它命令继续处理的时候,遇到了上面这种状况。好比 git log 命令,git log 直接在终端上执行是有颜色的,git log > git.log; cat git.log; 就没有颜色了。这个时候咱们须要用到 script 命令,再用上面本身写的小程序演示一下好了:
$ ./foo | cat 非终端 $ script -qc ./foo | cat 终端 |
script 命令能够骗过 foo 命令,让它觉得本身的标准输出是个终端。script 命令的 -c 选项就是专门干这个的:
-c COMMAND
Run the COMMAND rather than an interactive shell. This makes it easy for a script to capture the output of a program that behaves differently when its stdout is not a tty.
在 Bash 中,也有相似 c 语言中 isatty 函数功能的东西,就是 -t fd 条件表达式:
$ cat foo.sh if [[ -t 1 ]];then echo 终端;else echo 非终端;fi $ ./foo.sh 终端 $ ./foo.sh | cat 非终端 $ script -qc ./foo.sh | cat 终端 |