Dialog in Bash Is Not Grabbing Variables Correctly

Dialog in bash is not grabbing variables correctly

You can use that method to capture dialog otput directly into variable:

exec 3>&1 
result=$(dialog --menu head 15 20 6 $(for ((i=1;i<30;i++));do echo tag$i item$i;done) 2>&1 1>&3);
exitcode=$?;
exec 3>&-;
echo $result $exitcode

http://mywiki.wooledge.org/BashFAQ/002

so with my approach startup will look like:

startup()
{
exec 3>&1
_return=$(dialog --menu "Tiers are currently set as the following. Which would you like to update? \n" 12 78 5 \
"Stable" "$(cat ${DIR}/.tiers|grep Stable|sed 's/Stable=//g')" "Release" "$(cat ${DIR}/.tiers|grep Release|sed 's/Release=//g')" "Beta" "$(cat ${DIR}/.tiers|grep Beta|sed 's/Beta=//g')" 2>&1 1>&3)
exitcode=$?
exec 3>&-;
# OK is pressed
if [ "$exitcode" == "0" ] ; then
if [[ "$_return" == "Stable" || "$_return" == "Release" || "$_return" == "Beta" ]]
then
stable
fi
fi
echo "You have now exited the application"
clean_up;
}

additionaly many unclean things like $(${VERSION}) here:

dialog --msgbox "WARNING!!!!\n\n The folder $(${VERSION}) does not

as i understand from code it will run empty command as .version is empty on startup and

 VERSION=`cat .version`

in tier_update_prompt()
$VERSION still empty string,

I tried to refactory your code, but it turn that it messed to much so suggestions:

  • get dialog results as i shown above
  • run functions with parameters:

#declaration
function_name() {
parameter=$1;
echo "$parameter"
}
var=value
#run function
function_name var

  • do not overcomplexity with ${VAR},
  • remember that double quotes expands, so echo "here is $var" instead of echo "here is $(echo ${var})"
  • use as less temporary files as you can for example: diff <(ls dir1) <(ls dir2)
  • do not keep working files in root directory (like /test/)
  • do not work as root
  • learn perl

How to return the result of a dialog question in a bash function

When you run dialog in command substitution $(), the stdout is not terminal any more.

You need to pass it to dialog :

#!/usr/bin/env bash
function BUL_askYesNo()
{
exec 3>&1
return $(dialog --yesno "$1" 0 0 2>&1 1>&3)
}
BUL_askYesNo Hello

But return is still not working. I think this is much simpler :

#!/usr/bin/env bash
function BUL_askYesNo()
{
dialog --yesno "$1" 0 0
}
BUL_askYesNo Hello

BASH: Dialog input in a variable

Basically you will use command substitution to obtain the output of a command into a variable. Like this:

date=$(date)

which writes the output of the date command to the variable $date.

But if we try the same with the dialog dialog command:

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

we get an empty screen! Why does this happen?

Explanation:

dialog outputs the user input on stderr, since stdout will already being used by ncurses to update the screen. Without output redirection being used, the command substitution will return the command's stdout into the variable - meaning the output of ncurses will not get printed on screen. However if you type something (you can't see anything while typing):

test<enter>

The text test will appear on screen. This happens because it will been written to stderr and stderr still points to the current terminal.

Note: You might expect the ncurses output in $user_input but $user_input is empty after the command. I assume that this happens because dialog will check if it's output is going to a tty and it won't output anything otherwise. (Haven't verfied that)

Solution:

We can exchange stderr and stdout using i/o rerouting. We will turn stderr into stdout and write the user input to the variable but on the other hand turn stdout into stderr which will make ncurses outputting to the screen:

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

In short: 3>&1 opens a new file descriptor which points to stdout, 1>&2 redirects stdout to stderr, 2>&3 points stderr to stdout and 3>&- deletes the files descriptor 3 after the command has been executed.

This gives us the final command:

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

mkdir "$user_input"

Parsing output of chained dialog

exec 3>&1
result=$( dialog --clear --title title --menu Choose: 20 70 4 1 a 2 b 3 c \
--and-widget --menu Choose: 20 70 4 1 x 2 y 3 z 2>&1 1>&3 )
exitcode=$?
exec 3>&-
echo "result = >$result<" "exit-code = >$exitcode<"
sep=$(echo -e "\t") # define the separator
x=${result%$sep*} # remove up from separator
y=${result#*$sep} # remove up to separator

echo "Choosen: x=$x y=$y"

See https://askubuntu.com/questions/491509/how-to-get-dialog-box-input-directed-to-a-variable for getting the result of dialog into a variable. Your code x=$(( indicates and arithmetic expansion, which is not properly finished. See man bash $((expression)) Why it doesn't end with an error is beyond me. The quotes around dialogs parameters result in 5 parameters, while you need 4 parameters plus one or more pairs of parameters.

The result string from dialog seems to be separated by a TAB. Working with a regex based on blank would not work.

sed is not needed, it can be done with (bash builtin) 'Parameter Expansion'.

The menu is still printed on stdout. exec 3>&1 creates a duplicate of stdout. 1>&3 directs the usual output to channel 3, which is a duplicate of 1. Normal output ends up in stdout.

2>&1 redirects stderr to stdout which ends up as content of the variable.

In case of an error the error message is in your variable. Some error handling is needed.

Could not test with Xdialog, but I would expect it to work too.

Capture both stdout and stderr in Bash

There is no way to capture both without temp file.

You can capture stderr to variable and pass stdout to user screen (sample from here):

exec 3>&1                    # Save the place that stdout (1) points to.
output=$(command 2>&1 1>&3) # Run command. stderr is captured.
exec 3>&- # Close FD #3.

# Or this alternative, which captures stderr, letting stdout through:
{ output=$(command 2>&1 1>&3-) ;} 3>&1

But there is no way to capture both stdout and stderr:

What you cannot do is capture stdout in one variable, and stderr in another, using only FD redirections. You must use a temporary file (or a named pipe) to achieve that one.

How to store standard error in a variable

It would be neater to capture the error file thus:

ERROR=$(</tmp/Error)

The shell recognizes this and doesn't have to run 'cat' to get the data.

The bigger question is hard. I don't think there's an easy way to do it. You'd have to build the entire pipeline into the sub-shell, eventually sending its final standard output to a file, so that you can redirect the errors to standard output.

ERROR=$( { ./useless.sh | sed s/Output/Useless/ > outfile; } 2>&1 )

Note that the semi-colon is needed (in classic shells - Bourne, Korn - for sure; probably in Bash too). The '{}' does I/O redirection over the enclosed commands. As written, it would capture errors from sed too.

WARNING: Formally untested code - use at own risk.

Variable as multiple command parameters ignore quotes in Bash

After parameter expansion, any quotes in the result are treated as literal characters, not syntax for escaping whitespace. The correct way to create a list of values is to use an array, which acts as a second layer of quoting to allow whitespace in each element. As a bonus, array assignments also allow for more readable formatting.

MAIN_MENU=(
1 'Create new image' # Comments can be added, as well
2 'Start image as overriding'
3 'Start image as snapshot'
4 'Install OS'
5 'Settings'
)
dialog --title "Title" --menu 'Choose operation:' 0 0 5 "${MAIN_MENU[@]}"

Why does my menu with select fail the first time?

This problem only occurs when you type the commands interactively, not in a script. The reason is that the line you type after the select line is being used as the response to the prompt. Since if isn't in the menu, it reports an error. Then it doesn't execute the if command, because it was read as the response to the prompt.

It's not a problem in a script because the commands in the script are not used as standard input.



Related Topics



Leave a reply



Submit