I have trouble using a command line executable. I need to pass a potentially empty string to a program from bash, but the string is stored in a bash variable.
The (minimal working example of the C++) program is:
// Compile with g++ main.cpp -o soexec
#include <iostream>
int main(int argc, char** argv) {
// shows what the program arguments are
for(size_t ind = 1 ; ind < argc; ++ind)
std::cout << " argv[" << ind << "]={" << argv[ind] << "}" << std::endl;
// real application code should go here
return EXIT_SUCCESS;
}
When I use the program without variables, I got the following, as expected:
$ ./soexec --paramName ""
argv[1]={--paramName}
argv[2]={} # empty string, as wanted
$ EMPTY_VARIABLE=
$ ./soexec --paramName "${EMPTY_VARIABLE}"
argv[1]={--paramName}
argv[2]={} # empty string, as wanted
However, if the command lines arguments are stored in a variable, I get an issue
$ VARIABLE_NAME=
$ ARGS="--paramName $VARIABLE_NAME"
$ ./soexec $ARGS
argv[1]={--paramName}
# no argv[2]!
I also tried
$ VARIABLE_NAME=\"\"
$ ARGS="--paramName $VARIABLE_NAME"
$ ./soexec $ARGS
argv[1]={--paramName}
argv[2]={""} # this time the string is no longer empty, it contains the quote...
How can in pass a potentially empty string in bash to a command-line program ?
Note: this question has been marked as a duplicate of When should I wrap quotes around a shell variable?. However, it not only about quote in shell variable, it is about variable stored in another variable.
PS: for more context, my initial (and now resolved) problem was:
What's the best way to pass an empty string as argument to boost::program_options?
>Solution :
The problem is not really storing the argument in a variable, but expanding it before its actual use by including it in the $ARGS string.
So my first suggestion would be to avoid that string and passing the arguments directly to the program, when possible:
./soexec --paramName "$VARIABLE_NAME"
However, when this is not possible (or for any reason you want to use the ARGS variable), then it’s better to use a bash array (tutorial), instead of a string, so that each variable can be expanded individually. For this, you use "${your_array[@]}" ([@] to retrieve all elements and the quotes to keep the spaces in each, if present).
declare -a ARGS
ARGS[0]="--paramName"
ARGS[1]="$VARIABLE_NAME"
./soexec "${ARGS[@]}"
If you don’t like using the indices, you can also just use the += operator to append values to the array.
declare -a ARGS
ARGS+=("--paramName")
ARGS+=("$VARIABLE_NAME")
# equivalent to
# ARGS+=("--paramName" "$VARIABLE_NAME")
./soexec "${ARGS[@]}"