find一个shell函数?
有没有办法find
执行我在shell中定义的函数? 例如:
dosomething () { echo "doing something with $1" } find . -exec dosomething {} \;
其结果是:
find: dosomething: No such file or directory
有没有办法find
的-exec
看到dosomething
?
由于只有shell知道如何运行shell函数,所以你必须运行一个shell来运行一个函数。 您还需要使用export -f
将您的函数标记为导出,否则子shell将不会inheritance它们:
export -f dosomething find . -exec bash -c 'dosomething "$0"' {} \;
find . | while read file; do dosomething "$file"; done
在{}
添加引号,如下所示:
export -f dosomething find . -exec bash -c 'dosomething "{}"' \;
这样可以纠正由find
返回的特殊字符造成的任何错误,例如名称中带有圆括号的文件。
Jak的回答很好,但有一些容易克服的缺陷:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
这使用null作为分隔符而不是换行符,因此使用换行符的文件名将会起作用。 它也使用-r
标志来禁用反斜杠转义,而不使用文件名中的反斜杠将不起作用。 它也清除了IFS
以便不会丢弃名称中潜在的空白空格。
让脚本调用它自己,将每个find的项作为parameter passing:
#!/bin/bash if [ ! $1 == "" ] ; then echo "doing something with $1" exit 0 fi find . -exec $0 {} \; exit 0
当你自己运行脚本时,它会find你正在查找的内容,并调用自己将每个查找结果作为parameter passing。 当脚本以参数运行时,它会执行参数上的命令,然后退出。
处理结果批量
为了提高效率,许多人使用xargs
来批量处理结果,但这是非常危险的。 因为有一个替代方法引入到find
,批量执行结果。
请注意,这种方法可能会带来一些警告,比如POSIX中的一个要求 – 在命令的末尾find
{}
。
export -f dosomething find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
会将许多结果作为parameter passing给bash
的单个调用, for
-loop遍历这些参数,在每个参数上执行函数dosomething
。
上面的解决scheme启动$1
参数,这就是为什么有一个_
(它代表$0
)。
逐一处理结果
以同样的方式,我认为最好的答案应该被纠正为是
export -f dosomething find . -exec bash -c 'dosomething "$1"' _ {} \;
这不仅更为理智,因为参数应该始终以$1
开始,而且如果find
返回的文件名对shell有特殊的含义,使用$0
也可能导致意外的行为。
对于那些正在寻找一个bash函数来执行当前目录中所有文件的给定命令的人,我已经从上面的答案中编译了一个:
toall(){ find . -type f | while read file; do "$1" "$file"; done }
请注意,它会打破包含空格的文件名 (见下文)。
作为一个例子,采取这个function:
world(){ sed -i 's_hello_world_g' "$1" }
假设我想在当前目录中的所有文件中将hello的所有实例更改为world。 我会做:
toall world
为了安全使用文件名中的任何符号,请使用:
toall(){ find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done }
(但你需要一个处理-print0
的find
,例如GNU find
)。
以这种方式执行一个函数是不可能的。
为了克服这个问题,你可以把你的函数放在一个shell脚本中,然后通过find
调用它
# dosomething.sh dosomething () { echo "doing something with $1" } dosomething $1
现在用它来查找:
find . -exec dosomething.sh {} \;
把函数放在一个单独的文件中,并find
执行。
Shell函数在它们定义的shell内部; find
将永远无法看到他们。
不直接,不。 查找是在一个单独的进程中执行,而不是在你的shell中执行。
创build一个与你的函数完成相同工作的shell脚本,并find-exec
。
我发现最简单的方法如下,重复一个单一的两个命令
func_one () { echo "first thing with $1" } func_two () { echo "second thing with $1" } find . -type f | while read file; do func_one $file; func_two $file; done
我会完全避免使用-exec
。 为什么不使用xargs
?
find . -name <script/command you're searching for> | xargs bash -c