Як зупинити команду find після першого матчу?


131

Чи є спосіб змусити findкоманду зупинитися відразу після пошуку першого матчу?


4
TheUnseen: Причина того, що він припиняється після п'яти результатів при передачі на голову -n 5, полягає в тому, що голова виходить після п'яти результатів. Коли головка виходить, труба закривається і посилає сигнал трубі програми, щоб вона також припинилася. Вибачте, що не відповіли вам безпосередньо, мабуть, для відповіді вам потрібно 50 репутацій.
Русте

Відповіді:


148

За допомогою GNU або FreeBSD findви можете використовувати -quitпредикат:

find . ... -print -quit

findЕквівалент NetBSD :

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) призведе до того, що деякі снаряди мовчать про цю смерть (але все одно повернуть ненульовий статус виходу).


3
У разі, якщо комусь потрібно перевірити, чи відповідає якийсь файл предикатам, зупиняючись, як тільки його знайдено, у Bash та GNU Find ви можете зробити: if [[ $(find ... -print -quit) ]]; then ...він просто перевіряє, чи знайти друковане щось взагалі.
Тобія

@Tobia Краще помістити $(…)частину в лапки, якщо ви використовуєте лише одні дужки ( [ … ]).
phk

@phk За винятком того, що я не використовую одиничні дужки (тому що вони жахливі), тому мені не потрібно використовувати лапки.
Тобія

2
@Tobia, [це стандартна команда. Розбирається не стільки команда, яка жахлива, скільки те, як аналогічні оболонки Борна аналізують командні рядки. [[...]]це ksh конструкція, яка має власні проблеми в різних оболонках. Наприклад, до недавнього часу [[ $(...) ]]він не працював zsh(вам потрібно [[ -n $(...) ]]). Крім у zshвас, вам потрібні цитати [[ $a = $b ]], у [[ =~ ]]несумісних відмінностях між реалізаціями та навіть між версіями для bash та декількома помилками в деяких. Особисто я віддаю перевагу [.
Стефан Шазелас

що таке ...? .
киб

11
find . -name something -print -quit

Скасовується після першої відповідності після друку.

Скасувати пошук після певної кількості збігів та друку результатів:

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

Дивно, але зараз голова припиняє струну після 5 матчів, хоча я не знаю як і чому.

Це дуже просто перевірити. Дозвольте знайти пошук у корені, що призведе до тисяч, а може й більше збігів, займаючи хоча б хвилину чи більше. Але при передачі в "head" "пошук" закінчується після вказаної кількості рядків, визначених у заголовку (за замовчуванням головка показує 10, використовуйте "head -n", щоб вказати рядки).

Зауважте, що це припиняється після досягнення "head -n" заданого числа символів нового рядка, і тому будь-яка відповідність, що містить кілька символів нового рядка, буде підрахована відповідно.


Я також спостерігав, що ця програма «припиняється після того, як голова робиться з її результатом», але не послідовно в оболонках. Я думаю, що це заслуговує власного запитання - на щастя, для того, щоб ухилитись, відповідь вже є у Bash StackOverflow : поведінка Head & Tail із сценарієм bash . Це дає мені достатньо інформації, щоб зробити висновок, що те, чи припиняється програма чи продовжується її виконання у фоновому режимі, залежить від її реакції на SIGPIPE - вбивство є типовим.
шавлія

Я мав на увазі "через * програми * / оболонки", але, мабуть, unix.stackexchange.com вважає за краще, щоб я записував це як другий коментар, а не дозволяв мені редагувати свій перший коментар (це зміна stackexchange, рішення щодо конкретного сайту). Також я бачу, що @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

1

grep також повертається, якщо використовується з прапором -m, так, з

find stuff | grep -m1 .

вона повернеться після першого рядка, надрукованого знахідкою.

Різниця між цим find stuff -print -quit | head -1полягає в тому, що якщо пошук буде досить швидким, греп може не встигнути зупинити процес вчасно (хоча це не дуже важливо), тоді як якщо пошук тривалий, він буде зайвим знайти, щоб надрукувати багато непотрібного лінії.

це натомість працює з зайняттям пошуку в скриньці, хоча, оскільки у грепса для заняття також є, -mвін насправді не потрібен

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

це випустить повідомлення про процес пошуку, отримавши (зазвичай) сигнал підписи, але цей вихід належить запущеній оболонці, а не команді find, тому він не возиться з командним висновком, тобто труби або переспрямовування будуть виводити тільки рядок відповідні знахідці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.