Inability to escape quotes in a variable held during a subroutine call

I'm trying to write a database call from a bash script and I'm having trouble shutting down my shell.

These are the bones of what I do.

#---------------------------------------------    
#! /bin/bash    
export COMMAND='psql ${DB_NAME} -F , -t --no-align -c "${SQL}"  -o ${EXPORT_FILE} 2>&1'    
PSQL_RETURN=`${COMMAND}`    
#---------------------------------------------

      

If I use echo to print the $ {COMMAND} variable, the output looks fine:

echo ${COMMAND}

      

screen output: -

#---------------    
psql drupal7 -F , -t --no-align -c "SELECT DISTINCT hostname FROM accesslog;" -o /DRUPAL/INTERFACES/EXPORTS/ip_list.dat 2>&1    
#---------------

      

Also if I cut and paste this screen it runs just fine.

However, when I try to execute the command as a variable in a subclass call, it throws an error. The error is in the psql client that the quotes have been removed from the $ {SQL} string. The error suggests that psql is trying to interpret terms in the sql string as parameters.

So, the string and quotes are correct, but the quotes around the $ {SQL} variable / string are interpreted by the sub-shell when invoking the call from the main script.

I have tried to avoid them using various methods: \", \\", \\\", "", \"" '"', \'"\', ... ...

As you can see from my "try everything" approach, I am not an expert and it drives me crazy.

Any help would be greatly appreciated.

Charlie101

+3


source to share


2 answers


Instead of storing the command in a var line, it's better to use a BASH array here:



cmd=(psql ${DB_NAME} -F , -t --no-align -c "${SQL}" -o "${EXPORT_FILE}")
PSQL_RETURN=$( "${cmd[@]}" 2>&1 )

      

+4


source


Instead of evaluating the contents of a string, why not use a function?

call_psql() {    
    # optional, if variables are already defined in global scope
    DB_NAME="$1"
    SQL="$2"
    EXPORT_FILE="$3"

    psql "$DB_NAME" -F , -t --no-align -c "$SQL"  -o "$EXPORT_FILE" 2>&1
}

      

then you can just call your function like:

PSQL_RETURN=$(call_psql "$DB_NAME" "$SQL" "$EXPORT_FILE")

      

It is up to you how much you think through the function. You can check for the correct number of arguments (using something like (( $# == 3 ))

) before invoking the command psql

.

Alternatively, you might prefer to keep it as short as possible:

call_psql() { psql "$1" -F , -t --no-align -c "$2"  -o "$3" 2>&1; }

      



To capture a command being executed for debugging purposes, you can use set -x

in your script. This will be the contents of the function, including the extended variables when the function (or any other command) is called. You can disable this behavior by using set +x

, or if you want it to be enabled for the entire duration of the script, you can change the shebang to #!/bin/bash -x

. This will allow you to completely save echo

throughout your script to see what commands are being executed; you can just enable set -x

for the section.

A very simple script example using the shebang method:

#!/bin/bash -x

ec() {
  echo "$1"
}
var=$(ec 2)

      

Running this script, either immediately after executing it or calling it with bash -x

, gives:

++ ec 2
++ echo 2
+ var=2

      

Removing -x

from the shebang or call causes the script to run silently.

+2


source







All Articles