仅当我的外壳“连接”到终端时,即仅当我的标准输入来自终端的输入并且我的标准输出(和标准错误?也许这并不重要)被打印/回显时,我才想执行某些操作一个终端。
我怎样才能做到这一点,而不直接依赖 GNU/Linux 细节(如/proc/self
)?
答案1
isatty
是一个检查这个的函数,以及-t
test
命令的标志可以通过 shell 脚本访问它:
-t 文件描述符
如果文件描述符编号为真文件描述符已打开并与终端关联。假如果文件描述符不是有效的文件描述符编号,或者如果文件描述符编号文件描述符未打开,或者已打开但未与终端关联。
您可以使用以下命令检查 FD 0(标准输入)是否为 TTY:
test -t 0
您可以对 FD 1 和 2 执行相同的操作来检查输出和错误流或全部:
test -t 0 -a -t 1 -a -t 2
如果描述符连接到终端,则该命令返回 0(成功),否则返回 false。
test
也可用作[
“括号测试”的命令:
if [ -t 0 ] ; then ...
是编写此条件的惯用方式。
答案2
只是在已经给出的很好的答案之上添加一个额外的注释。请注意,[ -t 0 ]
测试文件描述符 0 是否打开一个文件,该文件是具有 tty 行规则的设备文件(通常,这是通过检查无害的 termio(s) ioctl() 是否成功来完成的)。
另外,这并不一定意味着另一端有一个终端或终端模拟器(真正的用户在键盘上打字)(尽管在绝大多数情况下,可能是您关心的大多数情况下,这已经足够好了近似)。
tty 和 pty 设备还可用于数据传输或作为进程间通信机制。
例如,可以这样做:
(stty raw -echo; myscript) < /dev/ttyS0
将通过 RS232 接收到的内容传送至myscript
.
echo test | ssh -tt host myscript
的myscript
stdin 是一个 pty 设备(在sshd
另一端,最终(通过 ssh 连接)不是终端,而是由 提供的管道echo
)
要进一步检查 RS232 线路或 pty 的另一端是否有终端,您还可以检查变量是否$TERM
已设置且非空 ( [ -n "$TERM" ]
) 并发送设备状态报告通过该 fd 转义序列并检查您是否收到响应(除了 和[ -t 0 ]
)[ -n "$TERM" ]
。
printf >&0 '\e[5n'
\e[0n
大多数终端都会回复“a” 。
现在存在几个问题,所以我不建议这样做,除非您想检查这一点,因为您想运行可视化 TUI 应用程序(在这种情况下,您最好使用类似的库ncurses
,并且您宁愿发送设备标识转义序列来代替 DSR,以比通过 更精确地查询终端类型$TERM
:
- 值得庆幸的是,在大多数情况下,stdin 不是终端,它将以只读模式打开,这会导致
printf
失败,但如果 stdin 是以读+写模式打开的 tty 设备,则会产生副作用将该序列发送到另一端。例如,在上面的 ssh 示例中,实际上会将序列发送到终端(但回复不会出现在标准输入上) - 很难可靠且可移植地阅读回复。您需要暂时更改 tty 线路规则并一次读取一个字节。您还需要决定一个超时,如果没有看到回复,您将放弃并确定没有终端。如果您想考虑人们通过卫星连接拨入,这意味着很长的超时。
- 在后台从终端读取数据会使用 SIGTTIN 信号暂停脚本。