Bash script to convert TUI input to database output not working properly

bashdatabasescriptzenity

I have the following Bash script which captures TUI data (zenity) to be prepared for a database insert statement:

#!/bin/bash

INPUT=NULL,2,Van Tassel,NULL,5,6,,8

INPUT="$(echo $INPUT | ( IFS=, read a b c d e f g h ; echo "$a,${b}xxx,$c,$d,${e}xxx,${f}xxx,${g}}
xxx,${h}xxx" ))"

IFS=,; set -f; set -- $INPUT; out=
for i in "$@"; do
    case "$i" in
        "")    echo empty input not allowed; exit 0;;
        NULL)  out="$out,$i";;
        *xxx)  out="$out,${i/%xxx/}";;
        *)     out="$out,\$\$$i\$\$";;
    esac;
done
echo "${out:1}" 

On running this script I get the following error message:

./err.txt: line 4: Tassel,NULL,5,6,,8: command not found
empty input not allowed

There are two things wrong with this script and I do not know how to solve them. For one the entry Van Tassel will only work if it is entered as 'Van Tassel' or VanTassel which is not how multiple strings are received from the TUI interface.

The second problem is that the case "") does not work. If I run the same script again but write VanTassel instead of Van Tassel I get the following output instead of the message "empty input not allowed".

NULL,2,$$VanTassel$$,NULL,5,6,,8

This should not be the case as the 7th field is empty.

Anyone able to help with this?

Best Answer

  1. INPUT=NULL,2,Van Tassel,NULL,5,6,,8 is like foo=bar baz: run baz with foo variable being bar in the environment. In a shell script you need to quote or escape the space to suppress this behavior.

    In case of a static line, quoting the entire value is often the best solution:

    INPUT='NULL,2,Van Tassel,NULL,5,6,,8'
    

    In the posted code the line is static but in reality "multiple strings are received from the TU interface", right? In such case the solution may depend on how this happens.

  2. When you claim the output is NULL,2,$$VanTassel$$,NULL,5,6,,8, it's really

    NULL,2,$$VanTassel$$,NULL,5,6,}
    ,8
    

    because in your code there is ${g}} and a newline just after. Next time post the code you're testing or test the code you're posting. :)

  3. The case "") allegedly does not work because you're injecting xxx into the 7th field first! A field modified this way will never match the empty string; it will match *xxx. Then you remove xxx while building out and the field goes back to its original empty value.

  4. echo $INPUT is very fragile and may give you unexpected results. Unquoted $INPUT behaves like in this answer: splitting and filename generation (globbing) occur. Note when we use set -- $INPUT later, we do want splitting and we suppress globbing (set -f earlier). But your echo $INPUT is prone to both. Even if you use echo "$INPUT", this will still apply: Why is printf better than echo? In Bash you can do

    IFS=, read … <<<"$INPUT"
    
  5. Use read -r unless you know you don't want -r (see help read).

  6. Maybe INPUT should be input. Read this: naming conventions for variables in shell scripts.

Related Question