你有沒有留意過下面這種場景: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 終端 |