如何使 bash inputmenu 对话框在自动单击重命名的情况下启动?
How can I make a bash inputmenu dialog start with rename automatically clicked?
我正在尝试让 bash inputmenu
dialog
处理不同的类型,例如文件、日期、常规文本。单击编辑按钮,只会将用户发送到正确的对话框以检索输入。对于常规文本,我只想使用 inputmenu
的重命名功能。我不能让用户手动 select 重命名,因为我只想将重命名操作用于文本输入。使用重命名操作自动加载外观相同的对话框 selected,可以让我解决这个问题。
我试图通过更改文件描述符并传入
、\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=""
choice=""
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 向对话框发送输入后,它 returns 返回到终端:
#!/bin/bash
/usr/bin/expect <<EOD
set timeout 30
spawn ./dialog1 >/dev/tty
sleep 1
send " "
expect eof
EOD
NB
我完全清楚我正在尝试规避 dialogs
限制,这通常是一件坏事,因为它会导致更差的代码,更难维护并且可能具有不必要的依赖性。这个问题应该更多地被视为一种学习练习。实际上,它只有在特殊情况下或作为可选的附加功能才值得。我正在创建一个 api 制造商,我将让客户选择可选的增强功能,比如这个,需要一个 hackish 解决方案。
使用 --inputbox
var=$(dialog --output-fd 1 --inputbox test 10 10)
它会立即打开输入菜单,然后根据需要使用 $var
中的数据。
还要考虑这个:
list=(
1 aaa
2 bbb
3 ccc
)
selected=1
first() {
cmd=$(
dialog \
--output-fd 1 \
--default-button extra \
--default-item "$selected" \
--extra-button --extra-label "Edit" \
--inputmenu "Select action:" 22 76 20 "${list[@]}"
)
}
first
在 运行 first
函数之后,您将在 $cmd
中得到类似的东西:
$ echo $cmd
RENAMED 2 123
解析并使用此数据,例如:
sub=($cmd)
index=${sub[1]}
value=${sub[2]}
另请查看我如何在 sshto 项目
中管理对话框
我同意其他评论者的观点,这可能是一个非常糟糕的主意,但你开始吧:
我还没有想出如何使用 expect
来做到这一点,但是可以使用它的替代方法 empty
(sudo apt install empty-expect
in 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
拦截输入和输出并将它们附加到管道
- 必要的命令输出到'input'管道
- 然后 TTY 的实际 STDIN 被重定向到同一个管道
- 命令结果保存在临时文件中
- 当命令完成执行时,它会发送 Ctrl+C 到
cat
以停止重定向
- (否则
cat
没有意识到管道不再存在,因此用户必须再按一次 ENTER)
或许可以避免使用临时文件,但这会使代码更加复杂
我正在尝试让 bash inputmenu
dialog
处理不同的类型,例如文件、日期、常规文本。单击编辑按钮,只会将用户发送到正确的对话框以检索输入。对于常规文本,我只想使用 inputmenu
的重命名功能。我不能让用户手动 select 重命名,因为我只想将重命名操作用于文本输入。使用重命名操作自动加载外观相同的对话框 selected,可以让我解决这个问题。
我试图通过更改文件描述符并传入
、\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=""
choice=""
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 向对话框发送输入后,它 returns 返回到终端:
#!/bin/bash
/usr/bin/expect <<EOD
set timeout 30
spawn ./dialog1 >/dev/tty
sleep 1
send " "
expect eof
EOD
NB
我完全清楚我正在尝试规避 dialogs
限制,这通常是一件坏事,因为它会导致更差的代码,更难维护并且可能具有不必要的依赖性。这个问题应该更多地被视为一种学习练习。实际上,它只有在特殊情况下或作为可选的附加功能才值得。我正在创建一个 api 制造商,我将让客户选择可选的增强功能,比如这个,需要一个 hackish 解决方案。
使用 --inputbox
var=$(dialog --output-fd 1 --inputbox test 10 10)
它会立即打开输入菜单,然后根据需要使用 $var
中的数据。
还要考虑这个:
list=(
1 aaa
2 bbb
3 ccc
)
selected=1
first() {
cmd=$(
dialog \
--output-fd 1 \
--default-button extra \
--default-item "$selected" \
--extra-button --extra-label "Edit" \
--inputmenu "Select action:" 22 76 20 "${list[@]}"
)
}
first
在 运行 first
函数之后,您将在 $cmd
中得到类似的东西:
$ echo $cmd
RENAMED 2 123
解析并使用此数据,例如:
sub=($cmd)
index=${sub[1]}
value=${sub[2]}
另请查看我如何在 sshto 项目
中管理对话框我同意其他评论者的观点,这可能是一个非常糟糕的主意,但你开始吧:
我还没有想出如何使用 expect
来做到这一点,但是可以使用它的替代方法 empty
(sudo apt install empty-expect
in 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
拦截输入和输出并将它们附加到管道- 必要的命令输出到'input'管道
- 然后 TTY 的实际 STDIN 被重定向到同一个管道
- 命令结果保存在临时文件中
- 当命令完成执行时,它会发送 Ctrl+C 到
cat
以停止重定向- (否则
cat
没有意识到管道不再存在,因此用户必须再按一次 ENTER)
- (否则
或许可以避免使用临时文件,但这会使代码更加复杂