我尝试放入find
函数内部并使用以下最小工作示例捕获传递给该函数的参数:
功能DO { ls $(find .-type f -name "$@" -exec grep -IHl "TODO" {} \;) }
但是,当我执行时DO *.tex
,我得到“find:路径必须先于表达式:”。但是当我直接这样做时:
ls $(find .-type f -name "*.tex" -exec grep -IHl "TODO" {} \;)
然后我得到所有包含“TODO”的 TeX 文件。
我在DO
函数中尝试了很多事情,例如\"$@\"
,,,'$@'
我更改了引号,但行为仍然相同。
那么,如何强制在函数内部找到工作呢?
答案1
您的代码存在一些问题:
如果该模式与当前目录中的任何文件名匹配,则在调用该函数时该
*.tex
模式将被扩展。调用该函数时,DO
您必须将模式引用为'*.tex'
,"*.tex"
或。\*.tex
不需要
ls
。您已经拥有两者find
,并且grep
能够报告找到的文件的路径名。-name "$@"
"$@"
仅当包含单个项目时才能正常工作。使用的话会比较好-name "$1"
。对于允许多种模式的解决方案,请参见下文。
该函数可以写成
DO () {
# Allow for multiple patterns to be passed,
# construct the appropriate find expression from all passed patterns
for pattern do
set -- "$@" '-o' '-name' "$pattern"
shift
done
# There's now a -o too many at the start of "$@", remove it
shift
find . -type f '(' "$@" ')' -exec grep -qF 'TODO' {} ';' -print
}
像这样调用这个函数
DO '*.tex' '*.txt' '*.c'
会让它执行
find . -type f '(' -name '*.tex' -o -name '*.txt' -o -name '*.c' ')' -exec grep -qF TODO {} ';' -print
如果文件包含字符串 ,这将生成具有这些文件名后缀的文件的路径名列表TODO
。
要使用grep
而不是find
打印找到的路径名,请将-exec ... -print
位更改为-exec grep -lF 'TODO' {} +
。这会更有效,特别是当您有大量与给定表达式匹配的文件名时。无论哪种情况,您绝对不需要使用ls
.
为了允许用户使用
DO tex txt c
你的功能可以改为
DO () {
# Allow for multiple patterns to be passed,
# construct the appropriate find expression from all passed patterns
for suffix do
set -- "$@" '-o' '-name' "*.$suffix" # only this line (and the previous) changed
shift
done
# There's now a -o too many at the start of "$@", remove it
shift
find . -type f '(' "$@" ')' -exec grep -qF 'TODO' {} ';' -print
}
答案2
您需要将参数引用到函数中,否则 shell 会展开它并且函数会获取文件列表,而不是通配符掩码:
DO "*.tex"
然后您可以使用 just"$1"
代替"$@"
,因为只有一个参数。