在Sub-shell执行调用期间转义变量保持字符串中的引号时出现问题

时间:2014-08-13 19:53:07

标签: bash shell escaping

我正在尝试从bash脚本中编写一个数据库调用,并且我遇到了一个子shell剥离我的引号的问题。

这是我正在做的事情的骨头。

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

如果我使用'echo'打印$ {COMMAND}变量,输出看起来很好:

echo ${COMMAND}

屏幕输出: -

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

此外,如果我剪切并粘贴此屏幕输出,它执行得很好。

但是,当我尝试将命令作为子shell调用中的变量执行时,它会给出错误消息。 错误来自psql客户端,以及已从$ {SQL}字符串周围删除引号的效果。 该错误表明psql正试图将sql字符串中的术语解释为参数。

所以看起来字符串和引号是正确组合的,但是在从主脚本执行调用期间,子shell正在解释$ {SQL}变量/字符串周围的引号。

我试图使用各种方法逃避它们:\", \\", \\\", "", \"" '"', \'"\', ... ... 正如你从“尝试一切”的方法中看到的那样,我不是专家,这让我很生气。

非常感谢任何帮助。

Charlie101

2 个答案:

答案 0 :(得分:4)

而不是将命令存储在字符串var中,而不是在这里使用BASH数组:

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

答案 1 :(得分:2)

为什么不使用函数?

,而不是评估字符串的内容
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
}

然后你可以像下面这样调用你的函数:

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

完全取决于你如何精心制作这项功能。您可能希望在调用(( $# == 3 ))命令之前检查正确数量的参数(使用psql之类的内容。)

或者,也许您只是想让它尽可能短:

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

为了捕获为执行调试而执行的命令,您可以在脚本中使用set -x。这将是函数的内容,包括调用函数(或任何其他命令)时的扩展变量。您可以使用set +x关闭此行为,或者如果您希望在脚本的整个持续时间内启用此行为,则可以将shebang更改为#!/bin/bash -x。这样可以在整个脚本中明确echo来查找正在运行的命令;您只需打开set -x部分即可。

使用shebang方法的一个非常简单的示例脚本:

#!/bin/bash -x

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

在使其成为可执行文件或使用bash -x进行调用后直接运行此脚本会给出:

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

从shebang中删除-x或调用会导致脚本以静默方式运行。