第一次比赛之后如何停止find命令?


131

find找到第一个匹配项后,是否有办法强制命令立即停止?


4
TheUnseen:当通过管道将其连接到head -n 5时,它在五个结果之后退出的原因是因为head在五个结果之后退出。当喷头退出时,管道关闭并向其中的程序管道发送信号以终止。很抱歉没有直接回复您,显然您需要50点信誉才能回复。
Ruste 2015年

Answers:


148

使用GNU或FreeBSD find,您可以使用-quit谓词:

find . ... -print -quit

find相当于NetBSD :

find . ... -print -exit

如果您仅打印名称,并假设文件名不包含换行符,则可以执行以下操作:

find . ... -print | head -n 1

find在第一场比赛之后,这不会停止,但是可能取决于第二场比赛(或以后)的时间安排和缓冲时间。基本上,find当它试图输出某些head已经消失的东西时,将以SIGPIPE终止,因为它已经读取并显示了输入的第一行。

请注意,并不是所有的外壳程序findhead返回后都会等待该命令。ksh(当非交互时)和yash(仅当管道是脚本中的最后一个命令时)的Bourne shell和AT&T实现不会,而使其在后台运行。如果您希望在任何shell中看到该行为,则可以始终将以上内容更改为:

(find . ... -print &) | head -n 1

如果您不只是打印找到的文件的路径,还可以尝试以下方法:

find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;

(替换printf为该文件要执行的操作)。

这样做的副作用是find返回退出状态,反映出已被杀死的事实。

实际上,使用SIGPIPE信号而不是SIGTERM(kill -s PIPE而不是kill)将使某些shell对于该死亡更为沉默(但仍会返回非零退出状态)。


3
万一有人需要测试任何文件是否与谓词匹配,一旦找到一个谓词,就立即停止,在Bash和GNU Find中,您可以执行以下操作:if [[ $(find ... -print -quit) ]]; then ...它只是测试是否查找打印出的任何东西。
Tobia 2014年

@Tobia最好$(…)在仅使用单括号([ … ])的情况下将零件引号引起来。
phk

@phk除了我不使用单括号(因为它们太可怕了)之外,所以我不需要使用引号。
Tobia

2
@Tobia [是标准命令。该命令不是很可怕,而是类似Bourne的shell解析命令行的方式。[[...]]是一个ksh构造,在各种shell中都有其自身的问题。例如,直到最近[[ $(...) ]]才可用zsh(您需要[[ -n $(...) ]])。除了中的zsh,您需要用中的引号[[ $a = $b ]][[ =~ ]]在实现之间,甚至在bash的版本之间以及某些错误中,都有不兼容的区别。我个人更喜欢[
斯特凡Chazelas

是什么...?。
kyb

11
find . -name something -print -quit

打印完第一个匹配项后终止查找。

在特定数量的匹配并打印结果后终止查找:

find . -name something -print | head -n 5

出乎意料的是,尽管现在我不知道如何或为什么,head现在在5个匹配项后终止了字符串。

测试非常容易。只需让根目录下的搜索成为可能,这将导致成千上万次,甚至可能需要至少一分钟或更长时间才能进行更多的匹配。但是当通过管道传递到“ head”中时,“ find”将在head中定义的指定行数之后终止(默认head显示10,使用“ head -n”指定行)。

请注意,这将在“ head -n”达到指定的换行符字符计数后终止,因此包含多个换行符的任何匹配项都将相应计数。


我还观察到了这种“程序在完成输出之后终止程序”的现象,但跨壳的情况却不一致。我认为这有其自身的问题-幸运的是,对于bash来说,答案已经在StackOverflow的Bash:bash脚本的头尾行为中。这为我提供了足够的信息,可以得出结论,该程序是否在后台终止还是继续在后台执行取决于其对SIGPIPE的响应-默认为killing。
2015年

我的意思是“跨越* programs // shells”,但显然unix.stackexchange.com宁愿我将其记录为第二条评论,而不是让我编辑第一条评论(这是Stackexchange特定于站点的政策决定)。另外,我现在看到@Ruste在顶部评论了这种效果,因为我直接回答了问题,这最初并没有帮助我……
sage

2

出于娱乐目的,这是Bash中的一个懒惰的find生成器。本示例在当前目录中的文件上生成一个环。然后阅读您想要阅读的内容kill %+(也许只有1个)

#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT

coproc x while :; do
    find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
    read -r _
    printf '%s\0' "$x"
done
EOF

while
    echo >&${x[1]}
    IFS= read -rd '' -u "$x" 'files[n++]'
do
    printf '%q ' "${files[@]}"
    echo
    sleep .2
done

1

如果与flag -m一起使用,grep也会返回,因此

find stuff | grep -m1 .

它会在find打印的第一行之后返回。

两者之间的区别在于find stuff -print -quit | head -1,如果搜索足够快,则grep可能无法及时停止该进程(尽管实际上并不重要),而如果搜索时间较长,它将多余的时间打印出很多不需要的东西线。

相反,它可以与busybox查找一起使用,尽管因为busybox grep也-m确实没有它

find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;

这将吐出一条有关find进程已收到(通常)sigterm信号的消息,但是此输出属于正在运行的shell,而不是find命令,因此不会与命令输出混淆,这意味着管道或重定向将仅输出该行通过查找匹配。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.