bash - 如何将复杂的文件 glob 传递给子 shell?

标签 bash git shell sh

我正在尝试使用带有文件模式的 git ls-files 来获取已过滤的跟踪文件列表。 (我知道我可以用 grep et.al 做下面的事情,但我很好奇为什么它不起作用)

#!/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"
}

我正在使用的 glob 在从命令行调用 git ls-files 命令时有效

git -C $GIT_ROOT ls-files --full-name --cached {include,src}/**/*.{hpp,cpp,tpp,h,c}

但在采购脚本后调用 git_sources 命令时则不然。

问题:如何正确引用 glob 模式,以便将其传递给子命令,就像直接从命令行调用一样?

最佳答案

这可能是因为 shell 如何扩展存储在变量中的 glob 字符串。无论您使用哪个引号,shell 都不会将包含 glob 字符串的命令扩展到您可以应用过滤器的结果文件中。

shell 将在展开一个未加引号的变量后进行 globbing,但是因为大括号展开是在变量展开之前完成的(引用 Shell Expansions),glob 将找不到任何匹配的文件并且 shell 会留下原义的 glob 字符串

当你运行时

git -C $GIT_ROOT ls-files --full-name --cached {include,src}/**/*.{hpp,cpp,tpp,h,c}

Shell 将 --cached 部分之后的 glob 字符串扩展为 file1..fileN,具体取决于与您的 glob 定义匹配的文件数量,即 as

git -C $GIT_ROOT ls-files --full-name --cached file1 file2 ... fileN

但是当您的 glob 字符串被引用(从变量扩展)时,同样的事情不会发生,它被扩展为

git -C $GIT_ROOT ls-files --full-name --cached '{include,src}/**/*.{hpp,cpp,tpp,h,c}'

这是您未扩展的 glob 字符串。

推荐的方法是使用数组扩展 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[@]}"

始终使用引号来扩展 shell 变量(除非您有充分的理由不这样做,在大多数情况下是没有的),并且在文件名中使用不带 _ 的小写变量名。

关于bash - 如何将复杂的文件 glob 传递给子 shell?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56734145/

相关文章:

linux - 如何删除名称为 '' $'\r' 的文件?

node.js - 使用一个 bash 脚本运行两台 Node 服务器并接收控制台日志

c - "cd"命令在我的自定义 shell 中不起作用

linux - 在bash中用其他文件过滤一个文件

bash - 无法在 Terraform 中运行 shell 脚本

string - 如果变量名存储为字符串,如何获取变量值?

windows - Git 发出警告 : unable to rmdir

git - 为什么 `git show` 不提供有关重定向标准输出的分支信息?

git - 无法使用 -b <tagname> 直接克隆到 git 标签中

linux - 如何使用 find 和 head 移动文件