该程序mc
(午夜指挥官)并不打算用于命令替换,但我想知道为什么当这个程序(通常看起来像其他curses程序)用作命令替换目标时,不同的shell表现不同。
在里面鱼壳,发出以下命令将打印字符串“无法获取终端设置:设备的 ioctl 不适当 (25)\n\n”。
echo (mc) # fish command substitution syntax
另一个值得注意的有趣的事情是,此命令返回后,您可以发出命令jobs
来查看mc
进程是否已挂起。
sh、bash 和 zsh 中的等效命令会挂起 shell,我所说的挂起是指我无法使用 Cz/Cc 终止或挂起该命令。我可以从命令中恢复的唯一方法是终止我的 shell 进程并重新启动它(从不同的 shell)。
echo $(mc) # hangs in sh, bash, zsh
鱼壳为什么不挂?它如何以不同的方式处理诅咒或命令替换等以产生这种行为?我觉得这很重要,因为它可能是其他贝壳所拥有的理想属性;任何命令都不应该意外地导致 shell 完全无法运行。
编辑:回答这个问题的另一种方法是说明为什么以下程序在 Fish shell 中用作命令替换目标时会被挂起。与 一样mc
,它使用curses,但它被修改为在检测到stdin 不是tty 时重新打开stdin。这使得诅咒模式可以在除鱼之外的所有贝壳中使用。
#define _XOPEN_SOURCE
#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
// start curses mode
SCREEN* s = NULL;
FILE* out = stdout;
if(!isatty(fileno(stdout))) {
out = fopen("/dev/tty", "w");
// Should really test `out` to make sure that worked.
setbuf(out, NULL);
}
// Here, we don't worry about the case where stdin has been
// redirected, but we could do something similar to out
// for input, opening "/dev/tty" in mode "r" for in if necessary.
s = newterm(NULL, out, stdin);
printw("test");
getch();
endwin(); // end curses mode
delscreen(s);
puts("/home/matt");
return 0;
}
请参阅此问题以获取更多信息:https://stackoverflow.com/questions/17450014/ncurses-program-not-working-rightly-when-used-for-command-substitution。这段代码是我在 Stackoverflow 上发布的原始问题的解决方案。该解决方案适用于除鱼之外的所有贝壳。
编辑:尝试通过在 gdb 中启动 Fish 来查找更多信息。使用以下 gdb 命令序列并得到以下输出:
(gdb) break main
Breakpoint 1 at 0x41fe70: file fish.cpp, line 417.
(gdb) run -c echo (mc)
Starting program: /home/matt/builds/fish-shell/fish -c echo (mc)
Cannot get terminal settings: Inappropriate ioctl for device (25)
调试器在此暂停,不再产生任何输出。这很奇怪,因为 main 中的断点从未命中。在执行命令替换之前,fish shell 需要解析其命令行参数,但我不确定线程如何影响在调试器中观察这一点。
答案1
好吧,我想我知道发生了什么事。
您在执行时在 zsh 和 bash 中观察到的行为echo $(mc)
是由mc
.
当您正常运行时,按下+mc
时它不会做出反应,因为它会忽略.结束的方法是按 F10 并 Enter。CtrlcSIGINT
mc
当您运行时,echo $(mc)
输入会进入进程mc
,因此难怪当您按Ctrl+时c什么也不会发生,因为mc
忽略了SIGINT
。但是当你运行echo $(mc)
并按 F10 并 Enter 时,它就会做出反应。 (当我再次按 F10 并 Enter 时,它实际上退出了;它应该在第一次尝试时退出,但我不知道为什么它没有退出。)
从这个事实我推断出 Midnight Commander 正常运行,但它的输出被放入 shell 缓冲区中,因此稍后可以被echo
.我们应该认为正常的事情。
另外你认为 bash 和 zsh 挂了,但我想说它们不是挂着而是在等待echo
命令返回。但echo
只能在mc
返回时返回,只有按下 F10 和 Enter 时才会返回。这样我们还可以解释当您按Ctrl+时会发生什么z。通过按组合键mc
进入睡眠状态,就像您mc
正常跑步但echo
仍在等待睡眠一样mc
。
所以一切都是正常行为。除了鱼的行为之外。 Fish 似乎启动了echo ($command)
在后台运行的命令。这是有道理的,因为这样的命令通常不需要任何输入。对于为什么以及如何我没有答案。但输入后可以看到它在后台运行
echo (mc)
jobs