我写了一个shell脚本agit
,我用它来循环遍历子目录(使用pushd
/ popd
),并对每个目录执行git命令。当我尝试使用-m
开关进行提交时,遇到了麻烦。如果我输入
agit --debug -u commit -a -m "This is a test commit"
--debug
导致set -x
就在git调用之前,而-u
仅对未提交更改的子目录执行调用。
我回来了
> git commit -a -m "This is a test commit"
+ git commit -a -m '"This' is a test 'commit"'
fatal: Paths with -a does not make sense.
第一行只是一个echo
命令,显示了我期望发生的事情,第二行是Bash实际处理的命令。我认为错误是因为仅将-m
之后的第一个单词视为一条消息,而将其余单词视为路径。
作为命令解析的一部分,我通读了每个参数,找到了所有包含空格的地方,并将它们用引号引起来。
while [[ ${#@} > 0 ]]; do
_1=${1}
if [[ "${1}" == *" "* ]]; then
_1="\"${1}\""
fi
_AT="$(append "${_AT}" "${_1}")"
shift
done
在遍历每个子目录时,我只使用
git ${_AT}
我尝试使用sed
来转义空格,改用单引号,并且完全不更改参数,所有这些都具有相同的结果。
我能做些什么来防止bash
破坏包含空格的参数吗?
您可以在pastebin上看到完整的脚本。
答案 0 :(得分:1)
使用printf "%q"
包装参数。就是为了这个(如果您必须这样做...):
rick() {
local idx=1 i
for i; do
echo "\$$idx=\"$i\""
((idx++))
done
}
morty_pass() {
eval rick $(printf "%q " "$@")
}
morty_pass "this is a test commit" "second arg"
将输出:
$1="this is a test commit"
$2="second arg"
根据您的命令:
agit --debug -u commit -a -m "This is a test commit"
您可能只使用了两个班次。然后,您可以将"$@"
传递给git commit。
agit() {
arg="$1" # --debug
# parse debug
shift;
arg="-u"
shift
git "$@" # will run as expected
}
如果需要,请使用bash数组:
args=()
while (($#)); do
args+=("$1")
shift
done
git "${args[@]}"
但是实际上这仅仅是:
args=("$@")
git "${args[@]}"
请注意,${#@}
甚至可以使我感到惊讶。看起来像个有趣的bash怪癖。仅将$#
用于参数计数。