如何在Bash中等待子shell的结果?

时间:2018-03-27 14:14:17

标签: bash pipe pipeline subshell

我正在Bash中编写一个辅助函数,其任务是从STDIN读取一些值(每行一个,如ls -1),然后让用户以交互方式选择一个。之前,我会使用dmenu,但我想让它更强大,并提供没有X11存在的情况。我也不想依赖某些外部工具,所以我决定让shell内置select我的后备机制。我写了以下函数:

function menu-selector {
    if ! xhost &> /dev/null; then
        cat | dmenu -l 10
    else
        select choice in $(cat); do
            echo $choice
            break
        done
    fi
}

现在,当我在管道中使用menu-selector时,两个分支都可以正常工作,例如:

ls -1 | menu-selector

在这两种情况下,都会调用适当的机制(dmenuselect),并且函数会返回所选的值。 当我想在子shell中的某个地方使用我的函数时,麻烦就开始了。假设我现在想要这样的东西:

my_dir=$(ls -1 | menu-selector)
echo $my_dir

在X11情况下,弹出dmenu并等待我的操作,选定的值将传递回我的代码并打印出来。但是当我选择no-X11选项时,select会打印所有选项,但不是等待我的选择,而是返回一个空值。这里有什么区别,更重要的是,我如何让select以相同的方式工作,即阻止执行我的脚本,直到它得到我的回答。我猜测不同之处在于两种情况下使用的IO设备 - dmenu使用X根窗口而select使用STDIN / OUT,可能在子shell中处理不同。

1 个答案:

答案 0 :(得分:0)

这是因为运行菜单功能的子shell的标准输入填充了ls -1的输出,因此select无法读取。

尝试使用参数而不是stdin来提供选项,这样您就不会有混淆选项和选择:

function menu-selector {
    if ! xhost &> /dev/null; then
        echo "$@" | dmenu -l 10
    else
        select choice in "$@"; do
            echo $choice
            break
        done
    fi
}

并像

一样使用它
response=$(menu-selector $(ls -1))