I'm trying to create a Bash dialog form that has a variable number of input fields. This code, for example, is a static one that allows four pieces of information to be entered:
exec 3>&1
VALUES=$(dialog --ok-label "Submit" \
--backtitle "Test input form" \
--title " Type information in " \
--form "" 12 95 0 \
"Item 1 :" 1 1 "$Item1" 1 15 65 256 "Item 2 :" 2 1 "$Item2" 2 15 65 256 "Item 3 :" 3 1 "$Item3" 3 15 65 256 "Item 4 :" 4 1 "$Item4" 4 15 65 256 \
2>&1 1>&3)
exec 3>&-
That works fine. So now I thought I'd try this:
ITEMS=4; unset ITEMSTRING
for ((i=1; i<=$ITEMS; i++))
do
ITEMSTRING=$ITEMSTRING"\"Item $i :\" $i 1 \"\$Item$i\" $i 15 65 256 "
done
ITEMSTRING="$ITEMSTRING\\"
echo -e "$ITEMSTRING"
...which outputs this string: "Item 1 :" 1 1 "$Item1" 1 15 65 256 "Item 2 :" 2 1 "$Item2" 2 15 65 256 "Item 3 :" 3 1 "$Item3" 3 15 65 256 "Item 4 :" 4 1 "$Item4" 4 15 65 256 \
That string is identical to the one contained within the dialog script from before, so I thought I'd be able to do this:
exec 3>&1
VALUES=$(dialog --ok-label "Submit" \
--backtitle "Test input form" \
--title " Type information in " \
--form "" 12 95 0 \
$ITEMSTRING
2>&1 1>&3)
exec 3>&-
But that simply produces the error: "Expected 8 arguments, found extra 1." I tried double-quoting the $ITEMSTRING variable: "Expected at least 20 tokens for --form, have 5."
Is it possible to construct a dialog command dynamically in this sort of way? What can I try to get the ITEMSTRING variable to be interpreted as the text it actually contains?
The aim, obviously, is to be able to alter the value of ITEMS and thus construct a user input dialog that has 4, or 6, or 19 user input fields, depending on context.
Answers
Yes, it is possible to dynamically construct a dialog
command in Bash. The issue you're encountering is related to the way you're constructing the $ITEMSTRING
variable. Since dialog
expects individual arguments, you need to ensure that each element in the command is separated properly.
One way to achieve this is to store the arguments in an array instead of a single string. Here's how you can modify your script to achieve that:
ITEMS=4
ITEMS_ARGS=()
# Loop to construct the arguments for dialog command
for ((i=1; i<=$ITEMS; i++))
do
ITEMS_ARGS+=("Item $i :" $i 1 "\$Item$i" $i 15 65 256)
done
# Run the dialog command with the constructed arguments
exec 3>&1
VALUES=$(dialog --ok-label "Submit" \
--backtitle "Test input form" \
--title " Type information in " \
--form "" 12 95 0 \
"${ITEMS_ARGS[@]}"
2>&1 1>&3)
exec 3>&-
In this script:
- We define an array called
ITEMS_ARGS
to store the arguments for thedialog
command. - Inside the loop, we use the
+=
operator to append each set of arguments for an item to theITEMS_ARGS
array. - Finally, when running the
dialog
command, we expand the array using"${ITEMS_ARGS[@]}"
. This ensures that each element in the array becomes a separate argument in thedialog
command.
With this approach, you can dynamically construct the dialog
command with the desired number of input fields based on the value of the ITEMS
variable.