如果在等待“read -s”时中断,在子进程中运行 bash 会破坏 tty 的标准输出吗?

2024-05-21

正如@Bakuriu 在评论中指出的那样,这基本上与BASH:输入期间按 Ctrl+C 会中断当前终端 https://stackoverflow.com/questions/31808863/bash-ctrlc-during-input-breaks-current-terminal但是,我只能在 bash 作为另一个可执行文件的子进程运行时重现该问题,而不是直接从 bash 运行,而 bash 似乎可以很好地处理终端清理。我对为什么 bash 在这方面似乎被破坏的答案很感兴趣。

我有一个 Python 脚本,用于记录由该脚本启动的子进程的输出。如果子进程恰好是一个 bash 脚本,它在某个时刻通过调用read -s内置(-s,这可以防止回显输入的字符,这是关键),并且用户中断脚本(即通过 Ctrl-C),然后 bash 无法将输出恢复到 tty,即使它继续接受输入。

我将其简化为一个简单的例子:

$ cat test.py
#!/usr/bin/python
import subprocess as sp
p = sp.Popen(['bash', '-c', 'read -s foo; echo $foo'])
p.wait()

运行时./test.py它将等待一些输入。如果您键入一些输入并按 Enter 键,脚本将按预期返回并回显您的输入,并且不会出现任何问题。但是,如果您立即按“Ctrl-C”,Python 将显示以下内容的回溯:KeyboardInterrupt,然后返回到 bash 提示符。但是,您键入的任何内容都不会显示在终端上。打字reset<enter>然而,成功重置终端。

我对这里到底发生了什么感到有些茫然。

Update:我也成功地在没有 Python 的情况下重现了这个。我试图在 strace 中运行 bash,看看是否可以收集正在发生的任何事情。使用以下 bash 脚本:

$ cat read.sh
#!/bin/bash
read -s foo
echo $foo

Running strace ./read.sh并立即按下 Ctrl-C 会产生:

...
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon -echo ...}) = 0
brk(0x1a93000)                          = 0x1a93000
read(0, Process 25487 detached
 <detached ...>

其中 PID 25487 是read.sh。这使得终端处于相同的损坏状态。然而,strace -I1 ./read.sh只是中断./read.sh处理并返回到正常的、未损坏的终端。


这似乎与以下事实有关:bash -c开始一个非交互式壳。这可能会阻止它恢复最终状态。

要显式启动交互式 shell,您只需传递-ibash 选项。

$ cat test_read.py 
#!/usr/bin/python3
from subprocess import Popen
p = Popen(['bash', '-c', 'read -s foo; echo $foo'])
p.wait()
$ diff test_read.py test_read_i.py 
3c3
< p = Popen(['bash', '-c', 'read -s foo; echo $foo'])
---
> p = Popen(['bash', '-ic', 'read -s foo; echo $foo'])

When I run and press Ctrl+C:

$ ./test_read.py

我得到:

Traceback (most recent call last):
  File "./test_read.py", line 4, in <module>
    p.wait()
  File "/usr/lib/python3.5/subprocess.py", line 1648, in wait
    (pid, sts) = self._try_wait(0)
  File "/usr/lib/python3.5/subprocess.py", line 1598, in _try_wait
    (pid, sts) = os.waitpid(self.pid, wait_flags)
KeyboardInterrupt

并且终端未正确恢复。

如果我运行test_read_i.py文件以与我刚刚得到的相同的方式:

$ ./test_read_i.py 

$ echo hi
hi

没有错误,终端可以工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果在等待“read -s”时中断,在子进程中运行 bash 会破坏 tty 的标准输出吗? 的相关文章

随机推荐