TheUnseen: Причина, по которой он выходит после пяти результатов при передаче по каналу -n 5, заключается в том, что голова выходит после пяти результатов. Когда головка выходит, труба закрывается и посылает сигнал программе, которая также завершает работу. Извините, что не отвечаете непосредственно вам, очевидно, вам нужно 50 репутации, чтобы ответить.
Руст
Ответы:
148
В 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) приведет к тому, что некоторые оболочки будут более молчаливы об этой смерти (но все равно вернут ненулевой статус выхода).
В случае, если кому-то нужно проверить, соответствует ли какой-либо файл предикатам, и остановится, как только он будет найден, в Bash и GNU Find вы можете сделать следующее: if [[ $(find ... -print -quit) ]]; then ...он просто проверяет, найдено ли что-либо напечатанное вообще.
Tobia
@Tobia Лучше поместить $(…)деталь в кавычки, если вы используете только одинарные скобки ( [ … ]).
phk
@phk За исключением того, что я не использую одиночные скобки (потому что они ужасны), поэтому мне не нужно использовать кавычки.
Tobia
2
@Tobia, [это стандартная команда. Это не столько ужасная команда, сколько способ, которым борновые оболочки разбирают командные строки. [[...]]это конструкция ksh, которая имеет свои проблемы в различных оболочках. Например, до недавнего времени [[ $(...) ]]не работал в zsh(вам нужно [[ -n $(...) ]]). За исключением того zsh, что вам нужны кавычки [[ $a = $b ]], у них [[ =~ ]]есть несовместимые различия между реализациями и даже между версиями для bash, и некоторые ошибки в некоторых. Лично я предпочитаю [.
Стефан
что такое ...? ,
kyb
11
find . -name something -print -quit
Завершает поиск после первого совпадения после его печати.
Завершить поиск после определенного количества совпадений и распечатать результаты:
find . -name something -print | head -n 5
Как ни странно - голова теперь завершает строку после 5 совпадений, хотя я не знаю, как и почему.
Это очень легко проверить. Просто дайте как найти на корню , который приведет тысячи, может быть , даже больше матчей, принимая по крайней мере минуту или больше. Но когда по трубопроводу в «голову» «поиск» прекратится после указанного количества строк, определенных в заголовке (заголовок по умолчанию показывает 10, используйте «заголовок -n» для указания строк).
Обратите внимание, что это прекратится после того, как "head -n" достигнет указанного количества символов новой строки, и, следовательно, любое совпадение, содержащее несколько символов новой строки, будет учитываться соответствующим образом.
Я также наблюдал, что это «программа завершается после того, как голова покончила с выходным сигналом», но не всегда в разных оболочках. Я думаю, что это заслуживает отдельного вопроса - к счастью, для bash ответ уже находится в поведении StackOverflow Bash: Head & Tail со сценарием bash . Это дает мне достаточно информации, чтобы прийти к выводу, что от того, будет ли программа завершена или продолжает выполняться в фоновом режиме, зависит ее ответ на SIGPIPE - по умолчанию уничтожение.
Мудрец
Я имел в виду «между * программами * / оболочками», но, очевидно, unix.stackexchange.com предпочел бы, чтобы я записывал это как второй комментарий, а не разрешал мне редактировать свой первый комментарий (это стек-обмен, решение для конкретной политики сайта). Кроме того, теперь я вижу, что @Ruste прокомментировал этот эффект сверху, что изначально не помогло мне, так как я пошел прямо к ответам ...
мудрец
2
Для развлекательных целей, вот ленивый генератор поиска в 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не нужен
это выдаст сообщение о том, что процесс поиска получил (обычно) сигнал sigterm, но этот вывод принадлежит запущенной оболочке, а не команде find, поэтому он не связывается с выводом команды, то есть каналы или перенаправления будут выводить только строку соответствует найти.
Ответы:
В GNU или FreeBSD
find
вы можете использовать-quit
предикат:NetBSD
find
эквивалент:Если все, что вы делаете, это печатаете имя и предполагаете, что имена файлов не содержат символов новой строки, вы можете сделать:
Это не остановится
find
после первого матча, но, возможно, в зависимости от времени и буферизации после второго матча или (намного) позже. По сути,find
будет завершено с SIGPIPE, когда он попытается вывести что-то, когдаhead
уже нет, потому что он уже прочитал и отобразил первую строку ввода.Обратите внимание, что не все оболочки будут ожидать этой
find
команды послеhead
ее возвращения. Реализация оболочки Bourne и AT & Tksh
(если она не является интерактивной) иyash
(только если этот конвейер является последней командой в сценарии) не будут выполняться, оставляя ее работающей в фоновом режиме. Если вы предпочитаете видеть такое поведение в любой оболочке, вы всегда можете изменить приведенное выше:Если вы делаете больше, чем просто распечатываете пути найденных файлов, вы можете попробовать этот подход:
(замените тем,
printf
что вы будете делать с этим файлом).У этого есть побочный эффект
find
возвращения статуса выхода, отражающего факт, что это было убито все же.На самом деле, использование сигнала SIGPIPE вместо SIGTERM (
kill -s PIPE
вместоkill
) приведет к тому, что некоторые оболочки будут более молчаливы об этой смерти (но все равно вернут ненулевой статус выхода).источник
if [[ $(find ... -print -quit) ]]; then ...
он просто проверяет, найдено ли что-либо напечатанное вообще.$(…)
деталь в кавычки, если вы используете только одинарные скобки ([ … ]
).[
это стандартная команда. Это не столько ужасная команда, сколько способ, которым борновые оболочки разбирают командные строки.[[...]]
это конструкция ksh, которая имеет свои проблемы в различных оболочках. Например, до недавнего времени[[ $(...) ]]
не работал вzsh
(вам нужно[[ -n $(...) ]]
). За исключением тогоzsh
, что вам нужны кавычки[[ $a = $b ]]
, у них[[ =~ ]]
есть несовместимые различия между реализациями и даже между версиями для bash, и некоторые ошибки в некоторых. Лично я предпочитаю[
....
? ,Завершает поиск после первого совпадения после его печати.
Завершить поиск после определенного количества совпадений и распечатать результаты:
Как ни странно - голова теперь завершает строку после 5 совпадений, хотя я не знаю, как и почему.
Это очень легко проверить. Просто дайте как найти на корню , который приведет тысячи, может быть , даже больше матчей, принимая по крайней мере минуту или больше. Но когда по трубопроводу в «голову» «поиск» прекратится после указанного количества строк, определенных в заголовке (заголовок по умолчанию показывает 10, используйте «заголовок -n» для указания строк).
Обратите внимание, что это прекратится после того, как "head -n" достигнет указанного количества символов новой строки, и, следовательно, любое совпадение, содержащее несколько символов новой строки, будет учитываться соответствующим образом.
источник
Для развлекательных целей, вот ленивый генератор поиска в Bash. В этом примере создается кольцо для файлов в текущем каталоге. Прочитайте сколько хотите тогда
kill %+
(возможно только 1)источник
grep также возвращает, если используется с флагом
-m
, поэтому сон вернется после первой строки, напечатанной функцией find.
Разница между этим и тем
find stuff -print -quit | head -1
, что если поиск выполняется достаточно быстро, grep может не успеть вовремя остановить процесс (хотя это и не имеет значения), в то время как если поиск будет продолжительным, он найдет для печати много ненужного. линий.вместо этого он работает с сервисом busybox find, хотя, так как grep busybox также
-m
не нуженэто выдаст сообщение о том, что процесс поиска получил (обычно) сигнал sigterm, но этот вывод принадлежит запущенной оболочке, а не команде find, поэтому он не связывается с выводом команды, то есть каналы или перенаправления будут выводить только строку соответствует найти.
источник