在 bash 中,回显列表会删除“/”

在 bash 中,回显列表会删除“/”

我发现这个方便的 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 脚本会因为空格或其他特殊字符而卡住?

请注意,这解释了您的示例失败的原因,而不是原始脚本失败的原因。据我所知,原文中的所有内容都被正确引用。

相关内容