我喜欢使用以下模式在文件中搜索:
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"
,会发生以下情况:
- Bash 解析引号并将命令拆分为单词:
findinfiles
,{*.js,*.html,}
{release,dev,}
span
。 - Bash 展开大括号,产生单词列表
findinfiles
,*.js
,*.html
,release
,dev
,span
。 - Bash 将通配符模式扩展
*.js
为*.html
匹配文件名的列表。如果没有文件名与任一模式匹配,则将其保留。 - 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
,$excludes
shell 执行以下操作:- 将变量替换为其值。
- 只要变量包含 中存在的字符,就将变量拆分为单独的单词
IFS
。默认情况下,IFS
包含空白字符(空格、制表符和换行符)。 - 将每个单词视为通配符模式并将其扩展到匹配文件列表。如果没有匹配的文件,则保留该模式。
(为了避免这些扩展步骤,请在变量替换周围使用双引号,如
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)
通配符模式的形式,它匹配js
或html
。 (此选项激活其他模式形式,详细信息请参阅手册。)shopt -s globstar
激活匹配任何深度的子目录的模式**/
(即执行递归遍历)。- 要更改排除列表(我预计这种情况不会经常发生),请修改
fif_excludes
变量。
答案2
bash 扩展{a,b,}1
为a1 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'"
}