簡體   English   中英

如何在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=vanillaCOLUMNS=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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM