![](/img/trans.png)
[英]How to run command and detect if it's successful by C language in Linux?
[英]How to detect if a command is interactive or not in linux
我想保存特定子流程的輸出以供以后使用。 為此,我使用 tee 將輸出顯示到 stdout 和日志文件。 但是,當涉及到諸如 ncdu 或 htop 之類的交互式命令時,它當然無法將其正確寫入文件。 因此,我希望能夠在運行命令之前(我認為這是不可能的)或在讀取此類命令的混亂日志文件時知道命令是否是交互式的。 我會假設有一些東西是交互式程序寫入標准輸出的,而普通命令不會,這將使我能夠區分兩者。
“混亂的輸出”是與終端控制序列混合的輸出,最常見的是ANSI 轉義碼。
對於依賴 Curses 進行終端輸出的二進制文件,在未設置 TERM 環境變量或設置為空字符串的情況下運行命令,會導致命令失敗。 例如,
$ env TERM= htop
Error opening terminal: unknown.
這是因為這些標准庫會檢查 TERM 環境變量,以在終端數據庫中找到相應的條目。 ( tput實用程序也使用該數據庫,因此您可以使用tput clear
清除終端,使用tput reset
reset 將終端tput reset
為默認狀態(如果終端模式出現亂碼,則很有用),等等。)
要確定command
是否使用 ncurses/curses 或終端信息數據庫( terminfo支持,您可以運行例如ldd command | grep -qe 'libn*curses' -e 'libtinfo' && echo Yes || echo No
。但是,這do 只說明這些命令是否正確支持不同的終端,而不是它們是否需要終端才能工作。
然后還有腳本和工具,比如ls --color
,它們不使用curses 或terminfo 支持,而是直接發出ANSI 控制序列。 (在ls
的情況下,使用在LS_COLORS
環境變量中定義的序列,但僅當輸出到終端時。正如 mmeisson 在對原始問題的評論中所提到的,使用例如isatty(STDOUT_FILENO ) .)
在htop
的情況下,我們甚至不能使用啞終端(在運行命令之前將 TERM 設置為啞終端,即env TERM=dumb htop </dev/null &>output
),因為 htop 將任務列表呈現為所有空格! 很煩人。 至少在top
( env TERM=dump top </dev/null &>output
) 中,可以得到不錯的、朴素的 ASCII 輸出。
香草終端可能就足夠了。 在執行子進程或命令之前,設置TERM=vanilla
和COLUMNS=80
,例如env TERM=vanilla COLUMNS=80 htop </dev/null &>output
。 但是,盡管您現在從htop
獲得更多輸出,但仍然缺少換行符(因為 htop 僅使用光標移動,而 vanilla 終端沒有這些)。
可能還有另一個終端適合您,例如,生成的所有轉義序列都可以輕松檢測和過濾掉,但它足夠復雜,例如 htop 輸出是完整的。 不過我一個都不認識。 您可以創建一個,並將其添加到 terminfo 數據庫之一(例如/etc/terminfo/e/easy
)。 (您可以使用ls -1 {/etc,/lib,/usr/share}/terminfo/?/* | sed -e 's|^.*/||g' | sort
列出您機器上的所有 terminfo 文件。我的有 2700 多個。)
對於這類問題,有一個獨特的、“適當的”解決方案,但這並不容易。
不是僅使用連接到子進程的管道,而是通過posix_openpt() 、 grantpt() 、 unlockpt()和ptsname()使用適當的偽終端接口pty ,特別是 UNIX98 偽終端。 然而,主端——你的進程——必須表現得像一個真正的終端,並處理它所支持的所有控制序列(通過將 TERM 環境變量設置為終端類型)。
有一些終端模擬器庫和代碼可以重用於您自己的項目; 我立即想到的是VTE (它使用 GTK+ GUI 小部件作為終端顯示)和xterm本身; xterm 源代碼中的ctlseqs.txt
是 xterm 變體中使用的實際序列的絕佳列表。 另一個有用的項目是GNU screen 。
本質上,您的程序然后成為命令使用的終端,可以為命令提供輸入,並在終端顯示上執行命令想要執行的所有更改。 您需要做的就是以某種方式記錄這些更改。 (這通常稱為抓取,但作為偽終端主控,您實際上只需要決定您希望如何存儲終端內容:作為電影般的播放、某種尺寸的單個屏幕或其他方式。)
總的來說,我認為最好的選擇是使用TERM=xterm
或變體,或者TERM=ansi
,然后過濾或替換部分/大部分/所有轉義序列以獲得您想要的輸出。 將“move cursor to”命令替換為換行符,如果列大於 1(最左邊的列),則后跟適當數量的空格; 和帶有一個或多個換行符的“清除屏幕”。 它並不完美,但它應該可以作為一個簡單的狀態機(逐個字符讀取終端輸出,並使用標准 <stdio.h> 函數發出過濾后的輸出),並且對於大多數用途來說都足夠好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.