bash - 如何使 bash 输入菜单对话框开始时自动单击重命名?

标签 bash menu dialog

我正在尝试做一个 bash inputmenu dialog处理不同的类型,例如文件、日期、常规文本。单击编辑按钮,将简单地将用户发送到正确的对话框以检索输入。对于常规文本,我只想使用 inputmenu 的重命名功能.我不能让用户手动选择重命名,因为我只想将重命名操作用于文本输入。加载一个外观相同的对话框并自动选择重命名操作,这样我就可以解决这个问题。
What I'm trying to do
我试图通过更改文件描述符并传入 来实现这一点。 , \n\r字符作为输入,但没有运气。

#!/bin/bash

list=(aaa bbb ccc)
selected=1

function menu1()
{
    count=0
    declare -a items
    for item in "${list[@]}"; do
        items+=($((++count)) "$item")
    done
    echo -n '2 ' > tmp.txt
    exec 4<tmp.txt
    cmd=(dialog
        --input-fd 4
        --print-size
        --print-maxsize
        --extra-button --extra-label "Edit"
        --default-button extra
        --default-item "$selected"
        --inputmenu "Select action:" 22 76 20)
    exec 3>&1
    #choices=$("${cmd[@]}" "${items[@]}" <<< ' ' 2>&1 1>&3)
    choices=$("${cmd[@]}" "${items[@]}" 2>&1 1>&3)
    retVal=$?
    exec 3>&-
    readarray -t choices <<< "${choices}"
    choices="${choices[2]}"
    echo "choices=$choices"
    echo "retVal=$retVal"
    menuAction "$retVal" "${choices[0]}"
}

function menu()
{
    count=0
    declare -a items
    for item in "${list[@]}"; do
        items+=($((++count)) "$item")
    done
    cmd=(dialog
        --print-size
        --print-maxsize
        --extra-button --extra-label "Edit"
        --default-button extra
        --default-item "$selected"
        --inputmenu "Select action:" 22 76 20)
    exec 3>&1
    choices=$("${cmd[@]}" "${items[@]}" 2>&1 1>&3)
    retVal=$?
    exec 3>&-
    readarray -t choices <<< "${choices}"
    choices="${choices[2]}"
    echo "choices=$choices"
    echo "retVal=$retVal"
    menuAction "$retVal" "${choices[0]}"
}

function menuAction()
{
    retVal="$1"
    choice="$2"
    declare -a choice="${choice[0]}"
    if [[ "$retVal" -eq 3 ]]; then
        choice=(${choice[0]})
        if [[ "${choice[0]}" == "RENAMED" ]]; then
            let selected=choice[1]
            let index=choice[1]-1
            unset choice[0]
            unset choice[1]
            list[$index]="${choice[@]}"
        fi
    fi
    [[ "$retVal" -ne 1 ]] && menu
}

menu1
编辑
我几乎可以使用 expect 让它工作起来.不幸的是,在 expect 将输入发送到对话框后,它返回到终端:
#!/bin/bash

/usr/bin/expect <<EOD
    set timeout 30
    spawn ./dialog1 >/dev/tty
    sleep 1
    send " "
    expect eof
EOD
备注
我完全知道我试图规避 dialogs限制,这通常是一件坏事,因为它会导致更糟糕的代码,更难维护并且可能具有不必要的依赖项。这个问题应该被视为更多的学习练习。实际上,它仅在特殊情况下或作为可选的附加项才值得。我正在创建一个 api 制造商,我将让客户选择可选的增强功能,比如这个,需要一个黑客解决方案。

最佳答案

我同意其他评论者的看法,这可能是一个非常糟糕的主意,但您可以继续:
我还没想好如何用 expect 做到这一点,但它的替代方案是可能的,称为 empty ( sudo apt install empty-expect 在 ubuntu/debian 中)
也可以检测或忽略 Ctrl+C但不是两者 - 见评论。

#!/bin/bash

#temporary files
export MYTMP=/tmp/dialog_$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM
export MYPID=${MYTMP}_pid.tmp
export MYOUT=${MYTMP}_out.tmp
export MYINP=${MYTMP}_inp.tmp
export MYRSL=${MYTMP}_rsl.tmp

#record "real" TTY just in case (this should not be necessary in most cases)
export MYTTY=`tty`

#replace command between `dialog` and `;` with your desired command or shell script
empty -f -i ${MYINP} -o ${MYOUT} /bin/bash -c 'dialog --extra-button --extra-label "Edit" --default-button extra --inputmenu "Select action:" 22 76 20 x "xx" y "yy" >${MYTTY} 2>${MYRSL} ; kill -SIGINT `cat ${MYPID}`'

#send "ENTER" key
sleep 0.1
echo -n -e '\n' >${MYINP}

# How to input keystrokes:
# \n - enter
# \e\e - ESC
# \t - tab (next button)
# \x0e - up     (or \e[A on some terminals)
# \x10 - down   (or \e[B on some terminals)

##optional: delete whatever was in the input box by pressing "DEL" a bunch of times
#echo -n -e '\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~\e[3~' >${MYINP}

## to detect Ctrl+C uncomment next line of code
#trap "export CTRL_C_PRESSED=1" INT
## ...and replace -SIGINT with -SIGTERM on line that starts with:   empty -f ...
##(you cannot both detect and ignore the signal)
## you could then test if ${CTRL_C_PRESSED} is equal to 1

#save PID to a file and redirect user input into 'dialog'
/bin/bash -c 'echo $$ >${MYPID} ; exec cat >${MYINP}'
## to ignore Ctrl+C insert:   ; trap "" INT ;   in place of semicolon (;) on previous line
## ...and replace -SIGINT with -SIGTERM on line that starts with:   empty -f ...

##If you trap/ignore Ctrl+C the script may screw up the terminal
##in that case please run    reset    command to fix, it also clears the screen


# check result in the file as you normally do
echo "----Result: `cat ${MYRSL}` "


#remove temporary files/pipes
sleep 0.1
if [ -e ${MYPID} ]; then rm ${MYPID}; fi;
if [ -e ${MYINP} ]; then rm ${MYINP}; fi;
if [ -e ${MYOUT} ]; then rm ${MYOUT}; fi;
if [ -e ${MYRSL} ]; then rm ${MYRSL}; fi;

怎么运行的:
  • 实际命令在另一个 shell 中执行,但输出直接通过管道传输到 tty
  • empty拦截输入和输出并将它们附加到管道
  • 必要的命令输出到“输入”管道
  • 然后 TTY 的实际 STDIN 被重定向到同一管道
  • 命令结果保存在临时文件中
  • 当命令完成执行时,它会发送 Ctrl+C 到 cat停止重定向
  • (否则 cat 不会意识到管道不再存在,因此用户必须再按一次 ENTER)


  • 可以避免使用临时文件,但这会使代码更加复杂

    关于bash - 如何使 bash 输入菜单对话框开始时自动单击重命名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66199156/

    相关文章:

    regex - Zgrep 和 sed 不匹配包含减号 (-) 的行

    android - 在android中填充没有XML文件的弹出菜单

    css - 垂直 spry 菜单栏文本不会垂直居中

    android - 无法在未调用 Looper.prepare 的线程内创建处理程序

    python - 尝试从 bash 运行 Python 脚本时出现奇怪的 HTML 文档类型错误

    bash - 如何使用 Robot 框架在 bash 中获取源文件?

    调用 `exit` 时 Bash 脚本不会立即退出

    javascript - 菜单中的下拉列表在单击之前消失

    c++ - 我如何知道用于与我的串行端口通信的十六进制?

    javascript - 如何手动从 Bootstrap 中关闭 Web 模式对话框?