![](/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.