我正在尝试将git ls-files
与文件模式一起使用,以获取跟踪文件的过滤列表。 (我知道我可以对grep等人进行以下操作,但我很好奇为什么它不起作用)
#!/usr/bin/env bash
GIT_ROOT=$(git rev-parse --show-toplevel)
# only include stuff in src and include
SRC_PATTERNS="{include,src}/**/*.{hpp,cpp,tpp,h,c}"
# @brief Get list of files in git index with names relative to root
# @param $1 Any of the constraints git-ls-files knows (e.g. --cached)
function git_sources()
{
FILE_STRING=$(git -C $GIT_ROOT ls-files --full-name $1 $SRC_PATTERNS)
echo "$FILE_STRING"
}
从命令行调用git ls-files
命令时,我正在使用的glob起作用
git -C $GIT_ROOT ls-files --full-name --cached {include,src}/**/*.{hpp,cpp,tpp,h,c}
但是在获取脚本后调用git_sources
命令时不会。
问题:我如何正确地引用glob模式,以便将其传递给子命令,就像直接从命令行调用一样?
答案 0 :(得分:4)
可能是因为shell如何扩展存储在变量中的glob字符串。不管您使用shell的哪个引号, not 都不会将包含glob字符串的命令扩展到生成的文件中,您可以在该文件上应用过滤器。
Shell将在扩展未引用的变量之后进行glob,但是由于大括号扩展是在变量扩展之前完成的(参考Shell Expansions),因此glob将找不到任何匹配的文件,并且shell会保留原义的glob字符串< / p>
跑步时
git -C $GIT_ROOT ls-files --full-name --cached {include,src}/**/*.{hpp,cpp,tpp,h,c}
shell根据与您的glob定义匹配的文件数(例如as)将--cached
部分后的glob字符串扩展为file1..fileN
。
git -C $GIT_ROOT ls-files --full-name --cached file1 file2 ... fileN
但是当您的全局字符串用引号(从变量扩展)被引为
时,不是会发生同样的情况git -C $GIT_ROOT ls-files --full-name --cached '{include,src}/**/*.{hpp,cpp,tpp,h,c}'
这是未扩展的全局字符串。
推荐的方法是使用数组扩展glob定义的结果以生成文件名,并将带引号的数组扩展作为参数传递。将您的代码更改为以下代码。
SRC_PATTERNS=({include,src}/**/*.{hpp,cpp,tpp,h,c})
现在,数组已经存储了与您的glob定义匹配的文件列表,我们只需要将其传递给以下命令即可。 ${arr[@]}
是带引号的数组扩展,可确保文件名中的shell-meta字符不会导致名称被分割
git -C "${GIT_ROOT}" ls-files --full-name --cached "${SRC_PATTERNS[@]}"
始终使用引号扩展外壳变量(除非您有充分的理由,否则多数情况下不会这样做),并使用文件名中不含_
的小写变量名。