I am trying to make a bash inputmenu
dialog
handle different types, such as, files, dates, regular text. Clicking the edit button, will simply send the user to the correct dialog to retrieve the input. For regular text, I simply want to use the rename feature of inputmenu
. I cannot have the user manually select rename because I only want the rename action to be used for text inputs. Having an identical looking dialog load up with the rename action automatically selected, would allow me to solve this problem.
I've tried to achieve this by changing the file descriptor and passing in
, \n
and \r
characters as inputs but with no luck.
#!/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
Edit
I've nearly got it working using expect
. Unfortunately, after expect has sent input to the dialog, it returns back to the terminal:
#!/bin/bash
/usr/bin/expect <<EOD
set timeout 30
spawn ./dialog1 >/dev/tty
sleep 1
send " "
expect eof
EOD
NB
I am fully aware that I am trying to circumvent dialogs
limitations and this is usually a bad thing, as it results in poorer code that's harder to maintain and may have unnecessary dependencies. This question should be considered more of a learning exercise. Practically, it's only worthwhile in exceptional circumstances or as an optional extra. I am creating an api maker and I will be giving the client the choice of optional enhancements, such as this, that require a hackish solution.
I agree with other commenters that it's probably a very bad idea but here you go:
I haven't figured how to do that with expect
, but it's possible with its alternative called empty
(sudo apt install empty-expect
in ubuntu/debian)
It is also possible to detect or ignore Ctrl+C
but not both - see comments.
#!/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;
How it works:
empty
intercepts input and output and attaches them to pipescat
to stop the redirection
cat
does not realize that the pipe no longer exists so user has to press ENTER one more time)It may be possible to avoid temporary files but that would complicate the code even more
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With