如何检查我的 shell 是否正在终端中运行?

如何检查我的 shell 是否正在终端中运行?

仅当我的外壳“连接”到终端时,即仅当我的标准输入来自终端的输入并且我的标准输出(和标准错误?也许这并不重要)被打印/回显时,我才想执行某些操作一个终端。

我怎样才能做到这一点,而不直接依赖 GNU/Linux 细节(如/proc/self)?

答案1

isatty是一个检查这个的函数,以及-ttest命令的标志可以通过 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

myscriptstdin 是一个 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 信号暂停脚本。

相关内容