为什么使用zsh小部件执行交互式命令时会中断

时间:2019-08-17 19:07:38

标签: shell zsh

Zsh版本:

zsh 5.4.2(x86_64-ubuntu-linux-gnu)

代码(两个文件:.zshrc和交互式文件,都位于我的主目录中):

.zshrc:

source ./interactive

custom_execute(){
  echo
  exc0 $BUFFER
  BUFFER=""
  zle accept-line
}
zle -N custom_execute
bind_enter(){
  bindkey '^M' custom_execute
}

互动:

exc0(){
  echo exc0_begin
  cmd="$@"
  eval "$cmd"
  ret=$?
  echo exc0_end
  return $ret
}

场景:

打开一个新的shell,执行以下命令:

exc0 sudo apt remove gparted

在exc0之后执行什么命令并不重要,重要的是它需要用户从stdin中输入才能完成。就我而言,已经安装了gparted,它将询问我是否要删除它。

我使用ctrl + c终止命令,因为我确实不想删除gparted。 最后一行显示为:

Do you want to continue? [Y/n] ^C%

现在我输入以下命令:

bind_enter

之后:

sudo apt remove gparted

最后两行显示:

Do you want to continue? [Y/n] Abort.
exc0_end

在两种情况下,shell都要求输入我的sudo密码,该部分正在运行。但是当涉及到确认时,第二条命令中断了。问题:为什么?

1 个答案:

答案 0 :(得分:2)

如果直接从TTY读取(如sudo密码)有效,但从stdin读取(如常规提示)无效,则可以通过将TTY重定向到特定命令的stdin来解决此问题。应该从TTY读取。

因此:

exc0() {
  local ret
  echo exc0_begin
  "$@" </dev/tty; ret=$?
  echo exc0_end
  return "$ret"
}

注意:

  • </dev/tty意味着在有问题的命令期间,stdin从TTY重定向。
  • 我们将ret标记为局部变量,以避免污染全局名称空间。
  • 我们将分配移至ret并与生成要捕获的退出状态的命令所在的行相同(以减少将来在命令之间放置更改并因此修改{{1} })。
  • 我们删除了$?不必要的使用(并且引起了错误)。