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

ole*_*leq 4 bash quoting function arguments

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

grep --color=auto -iRnHr --include={*.js,*.html,} --exclude-dir={release,dev,} "span" .
Run Code Online (Sandbox Code Playgroud)

然而,我想把这个包装成一个像这样的 bash 命令:

findinfiles {*.js,*.html,} {release,dev,} "span"  // syntax is just a guessing
Run Code Online (Sandbox Code Playgroud)

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

function findinfiles() {
    echo $1, $2, $3
}
Run Code Online (Sandbox Code Playgroud)

然后:

me@pc ~> findinfiles {*.js,*.html,} {release,dev,} "span"
*.js, *.html, release
Run Code Online (Sandbox Code Playgroud)

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

谁能教我如何处理这些争论?

Gil*_*il' 5

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

  1. Bash 解析引号并将命令拆分为单词:findinfiles, {*.js,*.html,} {release,dev,} span
  2. Bash 扩展大括号,生成单词列表findinfiles, *.js, *.html, release, dev, span
  3. 猛砸扩展通配符模式*.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}"
}
Run Code Online (Sandbox Code Playgroud)

说明:

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

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

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

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

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

shopt -s extglob globstar
fif_excludes='release dev'
alias fif='grep --color=auto -inH $fif_excludes'
Run Code Online (Sandbox Code Playgroud)

运行命令,如

fif span **/*.@(js|html)
Run Code Online (Sandbox Code Playgroud)

说明:

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