如何处理 TTY?"/>
shell 如何处理 TTY?
我正在用 nodejs 编写一个虚拟 shell 来弄清楚它们是如何工作的,并且意识到我的理解存在漏洞。具体来说,在 NodeJS 中,您可以使用
process.<stream>.isTTY
检测 TTY 模式下的 shell。但是如果我使用以下命令生成我的 nodejs 实例
import cp from 'node:child_process';
const proc = cp.spawn('node', ['-p', 'Boolean(process.stdin.isTTY)']);
process.stdin.pipe(proc.stdin);
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stderr);
await new Promise((ok, err) => proc.once('exit', code => code == 0 ? ok() : err()));
而使用
{ stdio: 'inherit' }
会产生一些魔力,导致文件描述符被传递给子进程,并随之传递给 TTY 模式。
import cp from 'node:child_process';
const proc = cp.spawn('node', ['-p', 'Boolean(process.stdin.isTTY)'], { stdio: 'inherit' });
await new Promise((ok, err) => proc.once('exit', code => code == 0 ? ok() : err()));
在这里,打印了值
true
,而在上面,打印了false
或undefined
。
这意味着管道流和 TTY 模式之间存在差异。
我的问题具体是关于 BASH 或 FISH 等 shell 如何处理这个问题,以及实际的区别是什么。
子进程如何继承这种 TTY 模式,以及当用户希望将一个进程通过管道传输到另一个进程时会发生什么。允许您拆分窗格的外壳如何工作?我指的不是 XTerm 或 Konsole 等终端仿真器,而是可以显示两个同步进程的实际 shell,这两个进程似乎都启用了 TTY。
回答如下:我们暂时保留拆分窗格。另外,不要考虑继承 TTY 模式;在 shell 的上下文中,这个概念实际上没有任何价值。
我会做 bash,因为我不懂鱼。
您可以测试 shell 是否与 交互
[[ $- == *i* ]] && echo 'Interactive' || echo 'not-interactive'
如果你通过管道连接到一个 shell,这个 shell 将变得不可交互:
$ cat | bash
[[ $- == *i* ]] && echo 'Interactive' || echo 'not-interactive'
not-interactive
另一方面,
[ -t 0 ]
测试您的 shell 是否从 tty 读取。考虑以下脚本:
#!/bin/bash
[[ $- == *i* ]] && echo 'Interactive' || echo 'not-interactive'
[ -t 0 ] && echo 'connected to tty' || echo 'not connected to tty'
你可以用不同的方式运行它。在当前 shell 中:
$ . test.sh
Interactive
connected to tty
作为脚本:
$ bash test.sh
not-interactive
connected to tty
或在管道上:
$ echo | bash test.sh
not-interactive
not connected to tty
或强制与
-i
互动:
$ echo | bash -i test.sh
Interactive
not connected to tty
那么,什么决定了一个 shell 是否是交互式的?根据源代码:
A shell is interactive if the `-i' flag was given, or if all of
the following conditions are met:
no -c command
no arguments remaining or the -s flag given
standard input is a terminal
standard error is a terminal
在启动过程中,bash 测试这个:
if (forced_interactive || /* -i flag */
(!command_execution_string && /* No -c command and ... */
wordexp_only == 0 && /* No --wordexp and ... */
((arg_index == argc) || /* no remaining args or... */
read_from_stdin) && /* -s flag with args, and */
isatty (fileno (stdin)) && /* Input is a terminal and */
isatty (fileno (stderr)))) /* error output is a terminal. */
init_interactive ();
else
init_noninteractive ();
所以,bash 在 shell 启动时确定它。
关键是,TTY 并没有真正以不同的方式处理。当然,您可以测试 shell 是否是交互式的;您可以测试 shell 是否从 TTY 读取,仅此而已。 TTY 只是 shell 的文件描述符。在源代码中,您可以看到有测试 STDIN 是否是 TTY,但对于其余部分:shell 使用 STDIN,而不是 TTY 作为输入。 TTY 受到不同对待的假设是错误的。
更多推荐
shell 如何处理 TTY?
发布评论