首页 > 解决方案 > 在 n 次匹配后可靠地停止 bash 查找

问题描述

我正在尝试找到一种可靠的方法来在例如 10 次匹配之后停止/终止查找操作。下面的代码说明了一个不优雅的例子。

find . -type f -iname "*.txt" -exec myscript.sh \{\} \;

其中 myscript.sh 当前仅输出匹配文件的名称

我已经尝试了一些在这里找到的建议,例如管道进入 head -n 10 或管道进入 grep -m 10 。但这些并不能可靠地阻止查找。刷新事物之前的 Stdbuf 同样无济于事。

有可靠的方法吗?

我试过这些但没有成功:

find . -type f -iname "*.txt" -exec myscript.sh \{\} \; | head -n 10

find . -type f -iname "*.txt" -exec myscript.sh \{\} \; | head -n 10 && tail -f /var/log/kern.log & read -t 10 ;kill $!
find . -type f -iname "*.txt" -exec myscript.sh \{\} \; | grep -m .

标签: bashfind

解决方案


您不能阻止您的find命令在终止之前生成超过 10 个匹配项。shell并行运行,并且find可以在 shell 终止管道之前轻松地在其输出缓冲区中排队十多行输出。headfind

可以做的是重构管道,以防止它出现任何症状。例如,

find . -type f -iname "*.txt" -print0 |
head -z -n 10 |
xargs -r0 myscript.sh

这依赖于几个 GNU 扩展(即,打印以空字符结尾的文件名的选项,以及对应的-print0选项和同上),所以它不是可移植的,但如果你安装它,它应该可以在大多数 Linux 发行版以及其他地方工作标准实用程序的 GNU 版本(可能随后称为、等)。find-zhead-0xargsgfindgheadgxargs

空终止对鲁棒性很重要;如果您的文件名包含换行符head等。可以在中间切掉文件名,当然,xargs不知道某些换行符是文件名的一部分,而不是参数分隔符。即使您目前没有任何名称包含换行符的文件名,您也希望针对任何不是一次性的解决方案来防止这种情况 - 稍后当您遇到带有换行符的文件名时解决问题将是繁琐而复杂。

或者,重构-exec

find . -type f -iname "*.txt" -exec sh -c '
    for arg in $(seq 10); do
        myscript.sh "$1"
        shift
    done
    exit 222' _ {} +

exit 222应该导致find在第一次-exec调用后失败而中止。+after-exec使得find尽可能多的参数传入,类似于xargs. (如果文件名真的很长,和/或你的系统ARG_MAX真的很小,这可能会在第一次调用中接收不到十个文件,但我认为这种极端情况是病态的。)


推荐阅读