在 zsh 中使用 -u 和 -k 进行读取的问题

在 zsh 中使用 -u 和 -k 进行读取的问题

我正在开发一个使用 read -k 的 zsh 脚本。如果我像这样执行脚本 ( echo a | myscript),它将无法获取输入。显然,这是由于 -k 始终使用 /dev/tty 作为标准输入,并且您必须告诉 read 使用标准输入,如read -u0.

但是,如果我将其更改为 -u0 (这使得之前的情况有效)并在不重定向 tty 的情况下执行我的脚本,它会破坏脚本,它根本不会像在没有 -u0 的情况下执行它一样。

编辑:经过调试,问题似乎很简单,使用-u0后,-k1选项不再读取单个字符并停止。在这种情况下,read 的工作方式与没有 -k 时一样,只是缓冲所有输入并在 EOL 到达时立即保存它

编辑2:经过更多调试后,我知道这与原始模式无法与 -u0 一起使用有关。如果我在读取之前添加 stty raw/cooked 那么它就可以工作(除了现在使用 \r 而不是 \n 处理输入击键),但是当我使用非 tty stdin 执行它时它会中断。

有什么方法可以使两种模式兼容?

事实上,我想了解为什么脚本的行为完全不同,无论我是否使用 -u0 读取,fd0 默认情况下与 /dev/tty 相同

答案1

read -k(读N个字符)和read -q(读yn)有两种操作模式:

  • 默认情况下,他们从终端读取。他们将终端置于原始模式下以逐字节读取(根据需要读取所需数量的字符)而不是逐行读取。
  • 可以指示它们从现有文件描述符中读取(-u带有数字,或-p从用于与当前协进程通信的管道中读取)。在这种情况下,它们只是从文件描述符中读取。

没有选项告诉 zsh 从特定源读取,但如果从终端读取,则更改终端模式。不过,您可以自己安排:检查标准输入是否是终端,-u0如果是则不要通过。

if [[ -t 0 ]]; then
  read -k1 …
else
  read -k1 -u0 …
fi

相关内容