我有这个 zsh 函数:
f() {
/usr/bin/find . -type f | less
}
当我运行此函数时,使用 Ctrl+z 暂停,然后运行 fg,它显示zsh: suspended (tty output) /usr/bin/find . -type f |
并且我无法恢复。这是为什么?我该如何恢复?
arch% f
zsh: suspended /usr/bin/find . -type f |
arch% fg
[2] - continued /usr/bin/find . -type f |
zsh: suspended (tty output) /usr/bin/find . -type f |
zsh: suspended (tty output) /usr/bin/find . -type f |
arch%
如果我/usr/bin/find . -type f | less
直接从命令行运行而不将其作为函数,它将正常暂停和恢复。
这是影响 zsh 5.9 的一个错误。它已于 2022 年 11 月修复,但自 2024 年 12 月以来尚未发布任何版本。
如果你这样做:
find
11128 确实是具有和 的作业的 PGIDless
,并且恢复工作正常,但是:这次,11493 是 的 PID ,而不是同时具有和 的
less
作业的 PGID ,后者是 11492。find
less
因此,当
fg
尝试将作业放在前台时,它会执行一个tcsetpgrp(11493)
无法将该作业放在前台的操作,然后继续使用 SIGCONT 恢复所有进程,并且碰巧less
在恢复时执行了一个后台进程不允许执行的操作tcsetattr()
(该命令stty
通常执行的操作),因此整个进程组都会收到 SIGTTOU 信号并再次被暂停。此处的一个解决方法是将函数定义更改为:
也就是说,使用子 shell 而不是命令组作为函数主体,这样父进程只需要关心一个进程,不会造成混淆。
使用:
似乎也有效(尽管由于某种原因意味着额外的过程)。
作业控制是相当棘手的事情,特别是当像 zsh 或 ksh 那样,您尝试在当前 shell 中运行管道的右侧,以及像 zsh 或 AT&T ksh 那样,您尝试在复合命令中按下 ^Z 时获得更有用的行为(例如
f
此处的函数主体)。请注意,暂停时上面出现的额外 11501 进程
f
。它在那里,以便函数的其余部分可以在find
、less
恢复(使用fg
或bg
)后恢复并最终终止。看看在 bash 或 mksh 中如何操作:
然后点击 ^Z,
sleep
程序会暂停,但此时echo here
会运行!然后如果你,程序会恢复运行,但其余函数已经执行完毕!fg
sleep
请参阅代码中解释它的注释:
其中一个问题(我不知道它与这里讨论的问题有多少关系;编辑,可能没有考虑修复)是“超级作业”不是已暂停进程的父级,因此例如无法获取它们的退出状态:
echo "$?"
确实是在(sleep...)
终止后运行,而不是像在中那样在暂停时运行bash
,但$?
反映了暂停状态,而不是4
您所期望的。zshmisc(1)
正如上面的评论所暗示的那样,您可以找到或中描述的行为info zsh jobs
: