Answers:
由于只有外壳程序知道如何运行外壳程序功能,因此必须运行外壳程序才能运行功能。您还需要使用标记要导出的函数export -f
,否则子shell将不会继承它们:
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
find . -exec bash -c 'dosomething "$0"' {} \;
它,它将处理文件名中的空格(和其他奇怪的字符)...
export -f
会在bash的一些版本才能正常工作。这不是POSIX,不crossplatforn,/bin/sh
将有一个错误与它
find . | while read file; do dosomething "$file"; done
while read
for循环来解决我的问题;for item in $(find . ); do some_function "${item}"; done
雅克(Jak)的答案很好,但有一些容易克服的陷阱:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
它使用null作为分隔符而不是换行符,因此带有换行符的文件名将起作用。它还使用-r
禁用反斜杠转义的标志,如果没有文件名中的反斜杠将不起作用。它还清除,IFS
以使名称中潜在的尾随空白都不会被丢弃。
/bin/bash
但不会起作用/bin/sh
。真可惜。
{}
如下所示添加引号:
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
这可以纠正由于所返回的特殊字符而导致的任何错误find
,例如,名称中带有括号的文件。
{}
。这将破坏包含双引号的文件名。touch '"; rm -rf .; echo "I deleted all you files, haha
。哎呀。
-exec bash -c 'echo $0' '{}' \;
请注意,使用时bash -c
,$ 0是第一个参数,而不是脚本名称。
为了提高效率,许多人xargs
习惯批量处理结果,但这非常危险。因此,引入了另一种方法find
来批量执行结果。
请注意,尽管此方法可能附带一些警告,例如POSIX- 在命令末尾find
具有的要求{}
。
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
会将许多结果作为参数传递给的单个调用,bash
并且for
-loop遍历这些参数,并dosomething
在每个参数上执行函数。
上面的解决方案以开头的参数$1
,这就是为什么有一个_
(表示$0
)的原因。
同样,我认为应该将接受的最佳答案更正为
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
这不仅更加合理,因为参数应始终以开头$1
,而且$0
如果find
shell 返回的文件名具有特殊含义,则使用可能会导致意外行为。
让脚本自己调用,将找到的每个项目作为参数传递:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
当您单独运行脚本时,它会查找您要查找的内容,并通过将每个查找结果作为参数进行调用来进行调用。当脚本使用参数运行时,它将在参数上执行命令,然后退出。
find: ‘myscript.sh’: No such file or directory
如果开始作为bash myscript.sh
...
对于那些正在寻找将对当前目录中的所有文件执行给定命令的bash函数的人,我从上述答案中编译了一个:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
请注意,它与包含空格的文件名分开(请参见下文)。
例如,使用以下功能:
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
}
(但是您需要一个find
处理-print0
例如GNU的find
)。
作为参考,我避免使用以下情况:
for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
_script_function_call $i;
done;
在当前脚本文件中获取find的输出,并根据需要迭代输出。我确实同意接受的答案,但是我不想在脚本文件之外公开函数。
无法以这种方式执行功能。
为了解决这个问题,您可以将函数放在shell脚本中,然后从 find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
现在在查找中将其用作:
find . -exec dosomething.sh {} \;
dosomething $1
=> dosomething "$1"
并使用find . -exec bash dosomething.sh {} \;
将函数放在单独的文件中并开始find
执行。
Shell函数位于定义它们的Shell内部。find
将永远无法看到他们。
要为其他一些答案提供补充和说明,如果您对exec
或execdir
(-exec command {} +
)使用bulk选项,并且想要检索所有位置参数,则需要考虑$0
with 的处理bash -c
。更具体地说,考虑下面的命令,该命令bash -c
按上面的建议使用,并从找到的每个目录中简单地回显以“ .wav”结尾的文件路径:
find "$1" -name '*.wav' -execdir bash -c 'echo $@' _ {} +
bash手册说:
If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the
positional parameters, starting with $0.
在这里,'check $@'
是命令字符串,并且_ {}
是命令字符串之后的参数。请注意,这$@
是bash中的特殊位置参数,可扩展到从1开始的所有位置参数。还要注意,使用该-c
选项,第一个参数将分配给position参数$0
。这意味着,如果您尝试使用访问所有位置参数$@
,则只会获得从头开始的参数$1
。这就是为什么Dominik的答案使用_
,这是fill参数的伪参数的原因$0
,因此$@
,例如,如果我们使用参数扩展(例如在该答案中使用for循环),我们想要的所有参数都将在以后可用。
当然,类似于已接受的答案,bash -c 'shell_function $0 $@'
也可以通过显式传递来工作$0
,但同样,您必须记住这$@
不会按预期进行。
不直接,不。查找是在单独的进程中执行的,而不是在您的shell中执行。
创建一个shell脚本,该脚本执行与您的功能相同的工作,并找到可以的功能-exec
。
我会避免-exec
完全使用。为什么不使用xargs
?
find . -name <script/command you're searching for> | xargs bash -c
$0
。