Instead of using simple strings, build your command using arrays. Arrays provide a convenient interface: If a
is an array, then "${a[@]}"
(note the quotes) expands into each element of a
, without additional field splitting or globbing (so spaces, and things like wildcards, should remain intact).
Example:
$ a=(printf "|%s|\n" "foo bar" "*")
$ echo ${a[@]}
printf |%s|\n foo bar bin boot dev etc home lib lib64 lost+found mnt opt proc root run sbin srv sys tmp usr var
Note how the *
was expanded, and how the extra spaces between foo
and bar
were lost. But with the "${a[@]}"
, these are preserved:
$ echo "${a[@]}"
printf |%s|\n foo bar *
This is ideal for building commands. Now, you can do:
$ "${a[@]}"
|foo bar|
|*|
See? The arguments were retained perfectly.
So, do:
COMMAND=(/usr/bin/exiftool "$PATH_NAME")
"${COMMAND[@]}"
The main problem is here:
read $input
In bash, usually, $foo
is the value of the variable foo
. Here, you don't want the value, but the name of the variable, so it should be just:
read input
Similarly, in the if
tests, $yes
and $no
should be just yes
and no
, since you just want the strings yes
and no
there.
You could use a case
statement here, which (IMHO) makes it easier to do multiple cases based on input:
case $input in
[Yy]es) # The first character can be Y or y, so both Yes and yes work
echo "Hello!"
echo "Hello!" | festival --tts
;;
[Nn]o) # no or No
echo "Are you sure?"
echo "Are you sure?" | festival --tts
;;
*) # Anything else
echo "Please answer yes or no."
echo "Please answer yes or no." | festival --tts
;;
esac
You could wrap the two echo
statements and the use of festival
in a function to avoid repeating yourself:
textAndSpeech ()
{
echo "$@"
echo "$@" | festival --tts
}
case $input in
[Yy]es) # The first character can be Y or y, so both Yes and yes work
textAndSpeech "Hello!"
;;
[Nn]o) # no or No
textAndSpeech "Are you sure?"
;;
*) # Anything else
textAndSpeech "Please answer yes or no."
;;
esac
With $input
, bash replaces this with its value, which is nothing initially, so the read
command run is:
read
And read
by default stores the input in the variable REPLY
. So you can, if you want, eliminate the input
variable altogether and use $REPLY
instead of $input
.
Also have a look at the select
statement in Bash.
Best Answer
In bash version > 4.3, you can declare the
tables
variable as a nameref:The loop could be written more simply without indirection as