Bash 在子shell执行调用期间,在变量保留字符串中转义引号时出现问题
我试图从bash脚本中编写一个数据库调用,但是我遇到了一个问题,子shell将我的引用剥离掉了 这是我正在做的事情的核心Bash 在子shell执行调用期间,在变量保留字符串中转义引号时出现问题,bash,shell,escaping,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
#---------------------------------------------
#! /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}
屏幕输出:-
另外,如果我剪切并粘贴这个屏幕输出,它的执行也很好
但是,当我尝试在子shell调用中作为变量执行该命令时,它会给出一条错误消息。
该错误来自psql客户端,大意是从${SQL}字符串周围删除了引号。
该错误表明psql试图将sql字符串中的术语解释为参数
因此,字符串和引号的组合似乎是正确的,但是${SQL}变量/字符串周围的引号在从主脚本执行调用期间由子shell进行解释
我试着用各种方法来逃避它们:\”、\\”、\\\”、“、\”、\”、\“\”、…
正如你从我的“全力以赴”方法中所看到的,我不是专家,这让我发疯
任何帮助都将不胜感激
Charlie101与其将命令存储在字符串变量中,不如在此处使用BASH数组:
cmd=(psql ${DB_NAME} -F , -t --no-align -c "${SQL}" -o "${EXPORT_FILE}")
PSQL_RETURN=$( "${cmd[@]}" 2>&1 )
与其计算字符串的内容,为什么不使用函数呢
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")
函数的详细程度完全取决于您。在调用psql
命令之前,您可能希望检查参数的正确数量(使用类似($#==3))
)
或者,您可能更愿意将其尽可能简短:
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
会导致脚本无声运行。你好,anubhava。这非常有效,响应速度也非常快。你的方法显然比使用字符串要好,但我对shell数组一无所知。因此我很沮丧。再次感谢。Charlie101。不客气,很高兴它成功了。如果你可以点击我答案左上角的勾号,将答案标记为已接受。在这种情况下,当一个函数更好地表达了你的意思,更具可移植性且不难编写时,为什么要使用数组?@user108168,仅供参考,如果你想以这种方式捕获数组的内容,你可以将其粘贴回command行并保证它的工作方式与“${cmd[@]}”
相同,即:printf“%q'”${cmd[@]}"; echo
——如果没有printf“%q”
和引号,您将得到的并不总是保证在运行时与命令的行为完全相同。嗨,Tom Fenech。谢谢你的回复。你的回答也很有效。我相信你知道。我喜欢这样一个事实,那就是它很好,很普通,也可以做得很简单。很好,很容易理解。有没有一种简单的方法可以捕获函数的实际命令行输出,这样我就可以在错误陷阱中与$PSQL_返回消息一起使用它?如果从命令中删除重定向,它应该将输出保存到变量中。这就是你想要的吗?嗨,汤姆,如果你是指2>&1,那么就不是了。我确信你知道这是在将标准错误重定向到标准输出,这样这两个错误都将被分配给变量,如:PSQL\u RETURN=$(call\u PSQL)。但这并没有告诉我函数的确切命令调用是什么。当然,我可以查看代码,但是很容易忽略一些小问题,除非在complete命令中打开输入变量。对于anubhava的解决方案,我可以使用:${cmd[@]}获取命令和返回变量以获取执行后输出。是否存在${cmd[@]}的等效值?感谢Charlie101Hi Tom Fenech,因为上面的要求,我将标记anubhava作为解决方案。我认为您的解决方案通常是一个非常整洁和清晰的通用解决方案,但我需要捕获准确的命令输出以进行调试。谢谢你的帮助。我相信我会在其他地方使用它。现在我明白了您的意图,我编辑了我的答案,向您展示了如何以相同的方式使用函数。我建议您阅读,因为它包含了一些关于这个主题的有用信息。如果你决定改变主意,你仍然可以接受我的答案。BashFAQ#50,直接回答这个问题。@Charles当然可以,谢谢你的有用链接。
++ ec 2
++ echo 2
+ var=2