rah*_*hmu 35 solaris ksh find shell-script function
我在 Solaris 10 上使用 ksh (88)、bash (3.00) 和 zsh (4.2.1) 测试了以下内容。
以下代码不会产生任何结果:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
Run Code Online (Sandbox Code Playgroud)
这一发现不匹配多个文件(如更换-exec ...用-print),并从外面叫时功能完美的作品find调用。
以下是该man find页面的内容-exec:
-exec command 如果执行的命令返回一个,则为真
零值作为退出状态。结尾
命令必须以转义字符作为标点
分号 (;)。命令参数 {} 是
替换为当前路径名。如果
-exec 的最后一个参数是 {} 而你
指定 + 而不是分号 (;),
命令被调用的次数更少,
{} 替换为路径名组。如果
命令的任何调用都会返回一个
非零值作为退出状态,找到
返回非零退出状态。
我可能会做这样的事情:
for f in $(find somedir); do
foo
done
Run Code Online (Sandbox Code Playgroud)
但我害怕处理字段分隔符问题。
是否可以从调用中调用 shell 函数(在同一个脚本中定义,让我们不要理会范围问题)find ... -exec ...?
我既试过/usr/bin/find和/bin/find,得到了相同的结果。
Sté*_*las 34
Afunction是 shell 本地的,因此您需要find -exec生成一个 shell 并在该 shell 中定义该函数,然后才能使用它。就像是:
find ... -exec ksh -c '
function foo {
echo blan: "$@"
}
foo "$@"' ksh {} +
Run Code Online (Sandbox Code Playgroud)
bash允许通过带有 的环境导出函数export -f,因此您可以执行以下操作(在 bash 中):
foo() { ...; }
export -f foo
find ... -exec bash -c 'foo "$@"' bash {} +
Run Code Online (Sandbox Code Playgroud)
ksh88必须typeset -fx导出函数(不是通过环境),但它只能由由 执行的she-bangless 脚本使用ksh,因此不能与ksh -c.
另一种选择是:
find ... -exec ksh -c "
$(typeset -f foo)"'
foo "$@"' ksh {} +
Run Code Online (Sandbox Code Playgroud)
也就是说,用于typeset -f转储foo内联脚本中函数的定义。请注意,如果foo使用其他函数,您还需要转储它们。
aec*_*ley 10
使用 \0 作为分隔符并将文件名从生成的命令读入当前进程,如下所示:
foo() {
printf "Hello {%s}\n" "$1"
}
while read -d '' filename; do
foo "${filename}" </dev/null
done < <(find . -maxdepth 2 -type f -print0)
Run Code Online (Sandbox Code Playgroud)
这里发生了什么:
read -d '' 读取到下一个 \0 字节,因此您不必担心文件名中的奇怪字符。-print0使用 \0 而不是 \n 来终止每个生成的文件名。cmd2 < <(cmd1)cmd1 | cmd2除了 cmd2 在主 shell 中运行而不是在子 shell 中运行之外,与 cmd2相同。/dev/null以确保它不会意外地从管道中读取。$filename 被引用,因此外壳不会尝试拆分包含空格的文件名。现在,read -d和<(...)在zsh中时,bash和ksh 93u,但我不知道早期版本KSH。
这并不总是适用,但如果适用,这是一个简单的解决方案。设置globstar选项(set -o globstar在 ksh93 中,shopt -s globstar在 bash 中?4;在 zsh 中默认启用)。然后使用**/递归匹配当前目录及其子目录。
例如,find . -name '*.txt' -exec somecommand {} \;您可以运行
for x in **/*.txt; do somecommand "$x"; done
Run Code Online (Sandbox Code Playgroud)
相反find . -type d -exec somecommand {} \;,您可以运行
for d in **/*/; do somecommand "$d"; done
Run Code Online (Sandbox Code Playgroud)
相反find . -newer somefile -exec somecommand {} \;,您可以运行
for x in **/*; do
[[ $x -nt somefile ]] || continue
somecommand "$x"
done
Run Code Online (Sandbox Code Playgroud)
当**/对您不起作用时(因为您的外壳没有它,或者因为您需要一个find没有外壳类似物的选项),请在find -exec参数中定义函数。
如果您希望从脚本生成的子进程使用预定义的 shell 函数,则需要将其导出 export -f <function>
注意:export -f是 bash 特定的
因为只有shell才能运行shell函数:
find / -exec /bin/bash -c 'function "$1"' bash {} \;
Run Code Online (Sandbox Code Playgroud)
编辑:基本上你的脚本应该是这样的:
#!/bin/bash
function foo() { do something; }
export -f foo
find somedir -exec /bin/bash -c 'foo "$0"' {} \;
Run Code Online (Sandbox Code Playgroud)