2009-09-04 47 views
2

我将参数存储在变量中的命令中。最后一个命令我想要的是:在bash变量内引用不受尊重

mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm 

这里是我的尝试:

set -x # for debugging 

RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS="-r $MOCK_CONFIG --define \"debug_package %{nil}\" --resultdir $RESULTDIR" 
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm" 
$cmd 

的结果是:

+ RESULTDIR=results 
+ MOCK_CONFIG=myconfig 
+ MOCK_ARGS='-r myconfig --define "debug_package %{nil}" --resultdir results' 
+ cmd='mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm' 
+ mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
ERROR: Bad option for '--define' ("debug_package). Use --define 'macro expr' 

正如你所看到的,参数传递给--define参数没有被正确引用。 --define认为我只通过它debug_package,这是不完整的。

我在尝试定义MOCK_ARGS时引号中的各种变体,甚至试图摆脱debug_package%{nil}之间的空格。

什么引号和/或转义组合允许我构建这个参数列表并执行该脚本中的命令?

编辑:

我存储在一个变量所得到的命令的原因是因为它最终被传递到其中做了一些记录的功能,然后执行该命令。

此外,我遇到this FAQ这表明我应该使用数组而不是变量。我已经开始尝试数组,但到目前为止还没有一个可行的解决方案。

+0

这看起来像是http://stackoverflow.com/questions/954390/echo-nested-quotation-marks-in-tcsh的副本 – 2009-09-04 06:48:57

+0

http://stackoverflow.com/questions/954390/echo- nested-quotation-marks-in-tcsh不适用于我。 – 2009-09-04 07:18:26

+0

可能的重复[如何执行bash命令存储为带有引号和星号的字符串](http://stackoverflow.com/questions/2005192/how-to-execute-a-bash-command-stored-as-a -string-with-quotes-and-asterisk) – 2015-07-05 08:37:28

回答

4

阵列是去为这样的事情的方式。以下是我想出了:

log_and_run() { 
    echo "$(date): running command: $*" 
    "[email protected]" 
    echo "$1 completed with status $?" 
} 

RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS=(-r "$MOCK_CONFIG" --define "debug_package %{nil}" --resultdir "$RESULTDIR") 
cmd=(mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm) 
log_and_run "${cmd[@]}" 
# could also use: log_and_run mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm 

注意$ *扩展用空格(适合传递给一个日志命令)分隔的所有参数;而“$ @”作为单独的单词扩展为所有参数(如在log_and_run中使用的,第一个将被视为执行的命令,其余为参数)。类似地,“$ {MOCK_ARGS [@]}”扩展为MOCK_ARGS的所有元素作为单独的单词,不管它们是否包含空格(因此MOCK_ARGS的每个元素都成为cmd的元素,没有引号分析混淆)。

此外,我引用了MOCK_CONFIG和RESULTDIR的扩展;这里没有必要这样做,因为它们不包含空格,但是如果它们碰巧包含空格(例如,它是否从外部传递到脚本中,那么它是很好的习惯),那么您应该假设它可能包含空格) 。

顺便说一句,如果您需要将其他参数传递给该函数(我将使用文件名的示例进行登录),则可以使用array slicing仅拆分后面的参数,以用作记录/执行:

log_and_run() { 
    echo "$(date): running command ${*:2}" >>"$1" 
    "${@:2}" 
    echo "$2 completed with status $?" >>"$1" 
} 
#... 
log_and_run test.log "${cmd[@]}" 

附录:如果你想引用在日志中包含的空间参数,可以在“手动”构建日志字符串,做任何引用你想要的。例如:

log_and_run() { 
    local log_cmd="" 
    for arg in "[email protected]"; do 
     if [[ "$arg" == *" "* || -z "$arg" ]]; then 
      log_cmd="$log_cmd \"$arg\"" 
     else 
      log_cmd="$log_cmd $arg" 
     fi 
    done 
    echo "$(date): running command:$log_cmd" 
    ... 

注意,这将处理在参数和空白参数空间,而不是(例如)内部参数双引号。这样做“正确”可以任意复杂...

此外,我构造log_cmd字符串的方式,它与一个前导空间;我通过在echo命令中省略之前的空间来处理上述情况。如果您需要实际修剪空间,请使用"${log_cmd# }"

+0

谢谢,这解决了我的问题!天才的中风是让一个完整的“模拟”命令成为一个阵列。这导致了我的'log_and_run()'函数的重构,它天真地使用'$ 1'来记录和运行命令而不是'$ *'和/或'$ @'。我无法得到''debug_package%{nil}“'的引号出现在日志中,但这是我可以忍受的一个小细节。 – 2009-09-06 09:30:43

4

Shell脚本可能很糟糕。在很多情况下,cmd="blah $blah";$cmdblah $blah不同。您可以尝试eval $cmd而不是$ cmd。

尝试调用此perl脚本,而不是模拟:

#!/usr/bin/perl 
print join("\n",@ARGV),"\n"; 

你可能会惊讶地看到参数列表居然是:

-r 
myconfig 
--define 
"debug_package 
%{nil}" 
--resultdir 
results 
--rebuild 
mypackage.src.rpm 

虽然我猜“设置-x”输出试图用单引号向你展示这一点。

一个好的技巧我最近了解到的情况是

function f { 
    echo "[email protected]" 
} 

其实正确转发位置参数到f($*没有)。

它看起来像 “EVAL” 带给你的,你可能打算:

set -x # for debugging 
RESULTDIR=results 
MOCK_CONFIG="myconfig" 
MOCK_ARGS="-r $MOCK_CONFIG "'--define "debug_package %{nil}" --resultdir '"$RESULTDIR" 
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm" 
echo $cmd 
eval $cmd 

输出:

+ echo mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm 
+ eval mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm 
++ mock -r myconfig --define 'debug_package %{nil}' --resultdir results --rebuild mypackage.src.rpm 
-r 
myconfig 
--define 
debug_package %{nil} 
--resultdir 
results 
--rebuild 
mypackage.src.rpm 
+2

谢谢 - eval是我的快速解决方案。 – 2011-09-10 23:56:53