我正在编写一个 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 的有问题的捕获/恢复下也是如此。