有没有办法找到执行我在shell中定义的函数?

例如:

dosomething () {
  echo "Doing something with $1"
}
find . -exec dosomething {} \;

其结果是:

find: dosomething: No such file or directory

有没有办法让find's -exec看到做某事?


当前回答

只是一个关于使用shell的接受答案的警告, 尽管它很好地回答了这个问题,但它可能不是在查找结果上执行某些代码的最有效方式:

这里是bash下的所有解决方案的基准测试, 包括一个简单的for循环的情况: (1465个目录,在一个标准硬盘驱动器上,armv7l GNU/Linux synology_armada38x_ds218j)

dosomething() { echo $1; }

export -f dosomething
time find . -type d -exec bash -c 'dosomething "$0"' {} \; 
real    0m16.102s

time while read -d '' filename; do   dosomething "${filename}" </dev/null; done < <(find . -type d -print0) 
real    0m0.364s

time find . -type d | while read file; do dosomething "$file"; done 
real    0m0.340s

time for dir in $(find . -type d); do dosomething $dir; done 
real    0m0.337s

“find | while”和“for loop”似乎在速度上最好且相似。

其他回答

因为只有shell知道如何运行shell函数,所以必须运行shell才能运行函数。你还需要用export -f标记你的export函数,否则子shell不会继承它们:

export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;

把函数放在一个单独的文件中,然后get find来执行它。

Shell函数在定义它们的Shell内部;Find永远也看不到他们。

以这种方式执行函数是不可能的。

为了克服这个问题,你可以把你的函数放在一个shell脚本中,然后从find调用它

# dosomething.sh
dosomething () {
  echo "doing something with $1"
}
dosomething $1

现在在find as中使用它:

find . -exec dosomething.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
}

(但是你需要一个处理-print0的find,例如GNU find)。

只是一个关于使用shell的接受答案的警告, 尽管它很好地回答了这个问题,但它可能不是在查找结果上执行某些代码的最有效方式:

这里是bash下的所有解决方案的基准测试, 包括一个简单的for循环的情况: (1465个目录,在一个标准硬盘驱动器上,armv7l GNU/Linux synology_armada38x_ds218j)

dosomething() { echo $1; }

export -f dosomething
time find . -type d -exec bash -c 'dosomething "$0"' {} \; 
real    0m16.102s

time while read -d '' filename; do   dosomething "${filename}" </dev/null; done < <(find . -type d -print0) 
real    0m0.364s

time find . -type d | while read file; do dosomething "$file"; done 
real    0m0.340s

time for dir in $(find . -type d); do dosomething $dir; done 
real    0m0.337s

“find | while”和“for loop”似乎在速度上最好且相似。