Variable number of inputs in a bash dialog inputbox

ghz 7months ago ⋅ 80 views

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 the dialog command.
  • Inside the loop, we use the += operator to append each set of arguments for an item to the ITEMS_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 the dialog 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.