Search code examples
bashformsdialog

Variable number of inputs in a bash dialog inputbox


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.


Solution

  • Hm ... not quite sure how to get the string interpreted properly in this case ... an interesting problem in itself ...

    But in general, when I want to pass arguments in this manner, some of which may be 'strings with spaces', the most reliable way is to capture each argument in an array, and then explode the array at the point of need.

    This worked for me:

    #!/bin/bash
    
    
    Item1="one"
    Item2="two"
    Item3="three"
    Item4="four"
    
    ITEMS=4;
    unset ITEMSTRING
    declare -a ITEMSTRING
    for ((i=1; i<=$ITEMS; i++))
    do
       ITEMSTRING[${#ITEMSTRING[@]}]="Item $i  :"
       ITEMSTRING[${#ITEMSTRING[@]}]="$i"
       ITEMSTRING[${#ITEMSTRING[@]}]=1
       REF="Item$i"
       ITEMSTRING[${#ITEMSTRING[@]}]="${!REF}"
       ITEMSTRING[${#ITEMSTRING[@]}]="$i"
       ITEMSTRING[${#ITEMSTRING[@]}]=15
       ITEMSTRING[${#ITEMSTRING[@]}]=65
       ITEMSTRING[${#ITEMSTRING[@]}]=256
    done
    
    exec 3>&1
    VALUES=$( 2>&1 1>&3 dialog --ok-label "Submit" \
          --backtitle "Test input form" \
          --title " Type information in " \
          --form "" 12 95 0 \
          "${ITEMSTRING[@]}"
    )
    exec 3>&-