2013-02-04 47 views
7

我想通過管道運行程序的輸出,但是當它檢測到stdout不是交互式shell時,它顯然表現不同。Bash:欺騙程序思想stdout是一個交互式終端

如何在正常情況下通過管道將它誘騙寫入?

+1

我聽說過' expect'是一個很好的程序 – BeniBela

+0

同時檢查'腳本'程序的目的:http://stackoverflow.com/a/1402389/516188 –

回答

12

我假定程序將調用glibc函數isatty()來檢查stdout是否是終端。對於在終端上使用彩色輸出的程序或ANSI終端的其他功能(如光標定位或行擦除/重繪),這是很常見的。

您可以使用LD_PRELOAD環境變量欺騙程序。 LD_PRELOAD由ELF鏈接器處理,並告訴動態庫應該在之前被加載。使用此功能可以重寫庫函數,在您的情況下glibc函數isatty()。例如,您可以按照此article

我準備了一個例子給你:

首先創建文件libisatty.c

/** 
* Overrides the glibc function. Will always return true. 
* 
* Note: Although this should be ok for most applications it can 
* lead to unwanted side effects. It depends on the question 
* why the programm calls isatty() 
*/ 
int isatty(int param) { 
    return 1; 
} 

並將其編譯爲一個共享庫:

gcc -shared -o libisatty.so libisatty.c 

它應該建立好。

現在是時候測試庫了。 :)我已經使用命令ls --color=auto進行測試。 ls調用isatty()來決定是否着色它的輸出。如果輸出重定向到文件或管道,則不會着色。您可以測試這一點很容易使用下面的命令:

ls --color=auto  # should give you colorized output 
ls --color=auto | cat # will give you monochrome output 

現在,我們將嘗試第二個命令再次使用LD_PRELOAD環境VAR:

LD_PRELOAD=./libisatty.so ls --color=auto | cat 

你應該看到彩色輸出。

BTW酷USENAME:uʍopǝpısdn!!:d

+1

只是...哇!神奇的答案! – slezica

+0

警告:創建一個執行'LD_PRELOAD'技巧的shell函數並不完美,因爲顯然其他的東西是shell函數中的其他可觀察的區別(我不確定它們是什麼)。然而,用別名​​'trick_tty'創建別名trick_tty' trick_tty =「LD_PRELOAD = <完整路徑>> /libisatty.so」'然後執行'trick_tty |少「的作品。 – ntc2

+1

對於MacOS用戶,您可以做同樣的事情,但不是設置LD_PRELOAD,而是設置DYLD_INSERT_LIBRARIES和DYLD_FORCE_FLAT_NAMESPACE,如下所示:'DYLD_INSERT_LIBRARIES =。/ libisatty.so DYLD_FORCE_FLAT_NAMESPACE = y ls -G | (注意--color標誌在mac的ls上不起作用) –

0

你可以試試這個:

./script.sh < `tty` > output 

如果程序做這樣的事情isatty(0),這可能是不夠的。

+3

請注意,程序在questio n會在stdout上運行isatty()。你把終端傳給stdin。這不會解決問題 – hek2mgl

+0

它可能實際上是測試stdin而不是標準輸出 – arnaud576875

+1

這沒有任何意義。 – hek2mgl

2

使用script作品對我來說:

script outputfile.txt yourcommand 
# any output ends up in outputfile.txt 

您可以使用它來管我猜:

script out.txt yourcommand ; cat out.txt | nextcommand 
+0

檢查'script'的源代碼應該揭示程序使用'isatty'之外的其他東西來判斷它們是否以交互方式運行。 – ntc2