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
INPUT=NULL,2,Van Tassel,NULL,5,6,,8
is likefoo=bar baz
: runbaz
withfoo
variable beingbar
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:
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.
When you claim the output is
NULL,2,$$VanTassel$$,NULL,5,6,,8
, it's reallybecause 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. :)The case
"")
allegedly does not work because you're injectingxxx
into the 7th field first! A field modified this way will never match the empty string; it will match*xxx
. Then you removexxx
while buildingout
and the field goes back to its original empty value.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 useset -- $INPUT
later, we do want splitting and we suppress globbing (set -f
earlier). But yourecho $INPUT
is prone to both. Even if you useecho "$INPUT"
, this will still apply: Why isprintf
better thanecho
? In Bash you can doUse
read -r
unless you know you don't want-r
(seehelp read
).Maybe
INPUT
should beinput
. Read this: naming conventions for variables in shell scripts.