我发现这个方便的 bash 函数用于选择并检查前一段时间的前一个分支。它就像一个魅力。关键位是:
BRANCHES=(
$(
git reflog |
egrep -io "moving from ([^[:space:]]+)" |
awk '{ print $3 }' | # extract 3rd column
awk ' !x[$0]++' | # Removes duplicates. See http://stackoverflow.com/questions/11532157
egrep -v '^[a-f0-9]{40}$' | # remove hash results
while read line; do # verify existence
([[ $CHECK_EXISTENCE = '0' ]] || git rev-parse --verify "$line" &>/dev/null) && echo "$line"
done |
head -n "$NUM"
)
)
if [[ $INTERACTIVE = '1' ]]; then
PS3="Choose a branch: "
select d in "${BRANCHES[@]}"; do
test -n "$d" && break
echo ">>> Invalid Selection"
done
git checkout "$d"
else
printf '%s\n' "${BRANCHES[@]}"
fi
我们的分行名称都是bug/...
或的形式task/...
。
由于某种原因,今天它开始失败。当我用 调试它时set -x
,我发现echo ${BRANCHES[@]}
似乎select
评估未引用的内容,正在删除/
.
为了简化/验证问题,我运行了以下命令:
foo=( "a/b" "c/d" )
echo $foo
# prints a b
echo ${foo[@]}
# prints a b c d
echo "${foo[@]}"
# prints a/b c/d
正如您所料,这个问题对我的别名/函数造成了严重破坏。
奇怪的是,虽然脚本中的函数打印:
1) master
task
2) 16658-...
task
3) 16525-...
Choose a branch:
foo
按预期从打印中选择:
select f in "${foo[@]}"; do
echo $f
break
done
# prompts:
# 1) a/b
# 2) c/d
所以我可能对根本原因是错误的,但我对此表示怀疑。1
在上面的提示中选择echo a b
。
实际上...
foo=a/b
echo $foo
# prints a b
echo "$foo"
# prints a/b
foo="a/b"
echo $foo
# prints a/b
如果重要的话,我在 Windows 上使用 git-bash 而不是 unix bash,但我无法想象这就是问题所在。
有任何想法吗?
答案1
当您回显未引用的内容时,它会受到所谓的 split+glob 的影响。这意味着您回显的内容将被拆分为变量中的任何字符IFS
,然后被视为一个 glob,如果它匹配任何内容,则该 glob 将被扩展。您在这里关心的部分是拆分。使用默认值IFS
(空格、制表符和换行符)不会发生您所描述的情况。如果您看到这种行为,那么您(或 shell 会话中的某些内容)已设置IFS
为其他内容,很可能是/
.为了显示:
$ foo=( "a/b" "c/d" )
$ echo ${foo[@]}
a/b c/d
## Now, change IFS
$ IFS='/'
$ echo ${foo[@]}
a b c d
## Of course, properly quoting fixes it
$ echo "${foo[@]}"
a/b c/d
## And so does un-setting IFS
$ unset IFS
$ echo ${foo[@]}
a/b c/d
这只是您应该始终引用变量的原因之一。有关更多信息,请参阅忘记在 bash/POSIX shell 中引用变量的安全隐患和为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?。
请注意,这解释了您的示例失败的原因,而不是原始脚本失败的原因。据我所知,原文中的所有内容都被正确引用。