使用 stty 正确恢复 tty

使用 stty 正确恢复 tty

我正在编写一个 bash 脚本来读取一些用户输入(例如密码请求),并且我想捕获结果并将其通过其标准输出传递。 (我正在 GNU/Linux 环境中工作,使用最新的软件)。

这是重现问题的脚本的简化版本

....

# read_input.sh
#
# Issue B : redirection of "3>&1" here causes stty error when                                             
# this script is executed via a command subsitution context subshell                                                                       
exec 3>&1 </dev/tty >/dev/tty                                                                                     

tty_settings=`stty -g`                                                                                            

# Issue A : uncommented version doesn't restore tty properly.                                                     
#trap 'stty "$tty_settings";' EXIT                                                                                
#trap 'echo "...interrupting"; exit 1' INT ABRT HUP QUIT TERM                                                     
trap 'echo "...interrupting"; stty "$tty_settings"; exit 1' INT ABRT HUP QUIT TERM                                

stty -echo                                                                                                        

echo "Enter input: "                                                                                              
input=""                                                                                                          
while IFS= read -r -n1 char; do                                                                                   
    # nb: stripped out proper char handling code here,                                                            
    # (except return), for simplicity                                                                             
    if [[ $char = "" ]]; then                                                                                     
        break
    fi
    input+=$char
    echo -n "*"
done
echo ""

stty "$tty_settings"

#trap - EXIT INT ABRT HUP QUIT TERM
trap - INT ABRT HUP QUIT TERM

echo "$input" >&3

目的是将结果输入写入 fd 3(如果调用时此脚本的标准输出连接在管道中),同时在交互期间仍然具有 tty。然后,我使用 stty 修改 tty 以控制 echo 等,通过 trap 处理来恢复任何修改。

我遇到了两个问题。


问题A

恢复到控制终端后,回声被抑制。我必须使用两行陷阱处理案例(已注释掉),而不是未注释的活动单行处理程序案例。

在一行情况下 - 比如说 INT :恢复 tty,然后通过处理程序调用 exit。我没有捕获 EXIT 本身 - 为什么需要这样做?


问题B

这与子 shell 上下文中 exec 的“3>&1”重定向有关。

出于某种原因,假设我在子 shell 中运行此脚本(“read_input.sh”),并希望通过命令替换从另一个脚本获取其输出:

....

# read_input_caller.sh
input=$(sh read_input.sh)
echo "$input"

我发现陷阱处理程序中的 stty 调用在中断调用脚本时抱怨以下内容(用 ^C 表示):

stty:'标准输入':输入/输出错误

该错误消息仅由于 exec 行中的“3>&1”重定向而发生 - 在没有“3>&1”的情况下调用该 exec 行,没有 stty 错误(但对于将输入传递到 stdout 不是很有用)。我想不通为什么会这样?

在调用脚本中,另一个子 shell 调用如

....

sh read_input.sh | cat

不会产生此错误。

有趣的是,当问题 B 发生时,控制终端的 tty 似乎已正确恢复,即使在问题 A 的有问题的捕获/恢复下也是如此。

相关内容