Bash:将大括号作为参数传递给 bash 函数

Bash:将大括号作为参数传递给 bash 函数

我喜欢使用以下模式在文件中搜索:

grep --color=auto -iRnHr --include={*.js,*.html,} --exclude-dir={release,dev,} "span" .

然而,我希望将这个包含在 bash 命令中,如下所示:

findinfiles {*.js,*.html,} {release,dev,} "span"  // syntax is just a guessing

$1我无法解决将这些类型的大括号传递到 bash 函数并将它们与,$2等一起使用的问题。当我使用以下内容时:

function findinfiles() {
    echo $1, $2, $3
}

然后:

me@pc ~> findinfiles {*.js,*.html,} {release,dev,} "span"
*.js, *.html, release

当然,将参数传递给 grep 不会以这种方式工作。似乎参数已索引但未正确分组。

谁能教我如何处理此类争论?

答案1

当你运行时findinfiles {*.js,*.html,} {release,dev,} "span",会发生以下情况:

  1. Bash 解析引号并将命令拆分为单词:findinfiles, {*.js,*.html,} {release,dev,} span
  2. Bash 展开大括号,产生单词列表findinfiles, *.js, *.html, release, dev, span
  3. Bash 将通配符模式扩展*.js*.html匹配文件名的列表。如果没有文件名与任一模式匹配,则将其保留。
  4. Bash 查找 name findinfiles,发现它是一个函数,并使用提供的参数执行该函数。

您可以防止在函数调用时扩展大括号和通配符,但是大括号将按字面意思出现在参数中,这并不是特别有用。

我建议更改函数调用的格式。不要使用大括号,而只使用逗号,并在函数内手动以逗号分隔参数。

findinfiles () {
  local patterns="$1" excludes="$2" pattern="$3"
  shift 3
  typeset -a cmd dirs
  if [[ $# -eq 0 ]]; then dirs=(.); else dirs=("$@"); fi
  cmd=(grep --color=auto -iRnHr)
  local IFS=,
  for x in $patterns; do
    cmd+=("--include=$x")
  done
  for x in $excludes; do
    cmd+=("--exclude-dir=$x")
  done
  "${cmd[@]}" "${dirs}"
}

说明:

  • 将前三个参数存储在局部变量中。任何额外的参数都是要搜索的目录。
  • 设置dirs为额外参数列表。如果没有,.则使用(当前目录)。
  • 设置IFS为逗号。当脚本包含像上面这样的不带引号的变量扩展时$patterns$excludesshell 执行以下操作:

    1. 将变量替换为其值。
    2. 只要变量包含 中存在的字符,就将变量拆分为单独的单词IFS。默认情况下,IFS包含空白字符(空格、制表符和换行符)。
    3. 将每个单词视为通配符模式并将其扩展到匹配文件列表。如果没有匹配的文件,则保留该模式。

    (为了避免这些扩展步骤,请在变量替换周围使用双引号,如patterns="$1"上面脚本中的等。)

  • 该函数构建命令行以在数组变量中增量执行cmd。最后,命令被执行。

或者,您可以基于以下设置进行构建:

shopt -s extglob globstar
fif_excludes='release dev'
alias fif='grep --color=auto -inH $fif_excludes'

运行如下命令

fif span **/*.@(js|html)

说明:

  • shopt -s extglob激活@(js|html)通配符模式的形式,它匹配jshtml。 (此选项激活其他模式形式,详细信息请参阅手册。)
  • shopt -s globstar激活匹配任何深度的子目录的模式**/(即执行递归遍历)。
  • 要更改排除列表(我预计这种情况不会经常发生),请修改fif_excludes变量。

答案2

bash 扩展{a,b,}1a1 b1 1..

您的命令扩展到grep --color=auto -iRnHr --include=*.js --include=*.html --include= --exclude-dir=release --exclude-dir=dev --exclude-dir= span(在没有任何 js 和 html 文件的目录中,否则它将包含每个文件)

您可以引用参数,但这可能并不理想...... findinfiles "{*.js,*.html,}" "{release,dev,}" "span"(那么仍然需要通配符)

然后您应该能够使用 正确扩展它eval,就像这个版本:

function findinfiles() {
    eval "grep --color=auto -iRnHr --include=$1 --exclude-dir=$2 '$3'"
}

相关内容