BASH: 变量中的对话框输入

BASH: Dialog input in a variable

我正在尝试使用 dialog 命令从输入框中获取用户输入,以在 bash 脚本中创建目录。目前我有以下代码:

 rm -f ans.txt
 dialog --title "Create Directory" --inputbox "Enter the directory name:" 8 40 2>ans.txt
 val=$(<ans.txt)
 mkdir $val

它可以工作,但是它需要创建(和删除)一个临时文件。我可以将来自 dialog 的用户输入直接存储到 $val 中而不使用临时文件吗?

基本上,您将使用命令替换将命令的输出获取到变量中。像这样:

date=$(date)

date 命令的输出写入变量 $date.

但是如果我们尝试使用对话框 dialog 命令进行相同操作:

user_input=$(dialog --title "Create Directory" --inputbox "Enter the directory name:" 8 40)

我们得到一个空屏幕!为什么会这样?

解释:

dialog 在 stderr 上输出用户输入,因为 ncurses 已经使用 stdout 来更新屏幕。如果不使用输出重定向,命令替换会将命令的标准输出 return 放入变量中——这意味着 ncurses 的输出不会打印在屏幕上。但是,如果您键入某些内容(键入时您看不到任何内容):

test<enter>

文本 test 将出现在屏幕上。发生这种情况是因为它将被写入 stderr,而 stderr 仍然指向当前终端。

注意: 您可能希望 $user_input 中的 ncurses 输出,但 $user_input 在命令后为空。我认为发生这种情况是因为 dialog 将检查它的输出是否要发送到 tty,否则不会输出任何内容。 (尚未验证)

解法:

我们可以使用 i/o 重新路由交换 stderr 和 stdout。我们会将 stderr 转换为 stdout 并将用户输入写入变量,但另一方面将 stdout 转换为 stderr,这将使 ncurses 输出到屏幕:

3>&1 1>&2 2>&3 3>&-

简而言之:3>&1 打开一个指向 stdout 的新文件描述符,1>&2 将 stdout 重定向到 stderr,2>&3 将 stderr 指向 stdout,3>&- 删除命令执行后的文件描述符 3

这给了我们最后的命令:

user_input=$(\
  dialog --title "Create Directory" \
         --inputbox "Enter the directory name:" 8 40 \
  3>&1 1>&2 2>&3 3>&- \
)

mkdir "$user_input"

请注意,Zenity 是一个 GUI 替代品。

如果您正在寻找文本界面,fzf 非常好。您可以轻松地重定向其输出:

var=$(print -l folder/* | fzf)

如果您只想读取用户输入:

var=$(echo '' | fzf --print-query)

这是 zsh 语法,我想 bash 用户会很容易地翻译它。

此外,fzf 与 tmux 交互良好。