Есть ли способ заставить find
команду остановиться сразу после нахождения первого совпадения?
Есть ли способ заставить find
команду остановиться сразу после нахождения первого совпадения?
Ответы:
В GNU или FreeBSD find
вы можете использовать -quit
предикат:
find . ... -print -quit
NetBSD find
эквивалент:
find . ... -print -exit
Если все, что вы делаете, это печатаете имя и предполагаете, что имена файлов не содержат символов новой строки, вы можете сделать:
find . ... -print | head -n 1
Это не остановится find
после первого матча, но, возможно, в зависимости от времени и буферизации после второго матча или (намного) позже. По сути, find
будет завершено с SIGPIPE, когда он попытается вывести что-то, когда head
уже нет, потому что он уже прочитал и отобразил первую строку ввода.
Обратите внимание, что не все оболочки будут ожидать этой find
команды после head
ее возвращения. Реализация оболочки Bourne и AT & T ksh
(если она не является интерактивной) и yash
(только если этот конвейер является последней командой в сценарии) не будут выполняться, оставляя ее работающей в фоновом режиме. Если вы предпочитаете видеть такое поведение в любой оболочке, вы всегда можете изменить приведенное выше:
(find . ... -print &) | head -n 1
Если вы делаете больше, чем просто распечатываете пути найденных файлов, вы можете попробовать этот подход:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(замените тем, printf
что вы будете делать с этим файлом).
У этого есть побочный эффект find
возвращения статуса выхода, отражающего факт, что это было убито все же.
На самом деле, использование сигнала SIGPIPE вместо SIGTERM ( kill -s PIPE
вместо kill
) приведет к тому, что некоторые оболочки будут более молчаливы об этой смерти (но все равно вернут ненулевой статус выхода).
if [[ $(find ... -print -quit) ]]; then ...
он просто проверяет, найдено ли что-либо напечатанное вообще.
$(…)
деталь в кавычки, если вы используете только одинарные скобки ( [ … ]
).
[
это стандартная команда. Это не столько ужасная команда, сколько способ, которым борновые оболочки разбирают командные строки. [[...]]
это конструкция ksh, которая имеет свои проблемы в различных оболочках. Например, до недавнего времени [[ $(...) ]]
не работал в zsh
(вам нужно [[ -n $(...) ]]
). За исключением того zsh
, что вам нужны кавычки [[ $a = $b ]]
, у них [[ =~ ]]
есть несовместимые различия между реализациями и даже между версиями для bash, и некоторые ошибки в некоторых. Лично я предпочитаю [
.
...
? ,
find . -name something -print -quit
Завершает поиск после первого совпадения после его печати.
Завершить поиск после определенного количества совпадений и распечатать результаты:
find . -name something -print | head -n 5
Как ни странно - голова теперь завершает строку после 5 совпадений, хотя я не знаю, как и почему.
Это очень легко проверить. Просто дайте как найти на корню , который приведет тысячи, может быть , даже больше матчей, принимая по крайней мере минуту или больше. Но когда по трубопроводу в «голову» «поиск» прекратится после указанного количества строк, определенных в заголовке (заголовок по умолчанию показывает 10, используйте «заголовок -n» для указания строк).
Обратите внимание, что это прекратится после того, как "head -n" достигнет указанного количества символов новой строки, и, следовательно, любое совпадение, содержащее несколько символов новой строки, будет учитываться соответствующим образом.
Для развлекательных целей, вот ленивый генератор поиска в Bash. В этом примере создается кольцо для файлов в текущем каталоге. Прочитайте сколько хотите тогда 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
grep также возвращает, если используется с флагом -m
, поэтому с
find stuff | grep -m1 .
он вернется после первой строки, напечатанной функцией find.
Разница между этим и тем find stuff -print -quit | head -1
, что если поиск выполняется достаточно быстро, grep может не успеть вовремя остановить процесс (хотя это и не имеет значения), в то время как если поиск будет продолжительным, он найдет для печати много ненужного. линий.
вместо этого он работает с сервисом busybox find, хотя, так как grep busybox также -m
не нужен
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
это выдаст сообщение о том, что процесс поиска получил (обычно) сигнал sigterm, но этот вывод принадлежит запущенной оболочке, а не команде find, поэтому он не связывается с выводом команды, то есть каналы или перенаправления будут выводить только строку соответствует найти.