limit find output AND avoid signal 13

1) установить build-essential

apt-get install build-essential

Перейдите в / usr / local / src floder

cd /usr/local/src

Загрузите последний пакет Curl из здесь с использованием:

wget http://curl.haxx.se/download/curl-7.48.0.tar.gz

Unzip

tar -xvzf curl-7.48.0.tar.gz
rm *.gz
cd curl-7.48.0
./configure
sudo make
sudo make install

2) Лучшая архитектура - amd64 `

7
20.03.2017, 12:18
3 ответа

Поскольку вы уже используете расширения GNU ( -quit , -H , -m1 ), вы также можете использовать GNU grep параметр -r вместе с - line-buffered , чтобы он выводил совпадения как можно скорее. как только они будут найдены, то SIGPIPE с большей вероятностью будет отключен, как только он напишет 6-ю строку:

grep -rHm1 --line-buffered pattern /path | head -n 5

С помощью find вам, вероятно, потребуется сделать что-то вроде:

find /path -type f -exec sh -c '
  grep -Hm1 --line-buffered pattern "$@"
  [ "$(kill -l "$?")" = PIPE ] && kill -s PIPE "$PPID"
  ' sh {} + | head -n 5

That есть, оберните grep в sh (вы по-прежнему хотите запускать как можно меньше вызовов grep , отсюда {} + ), и sh убить своего родителя ( find ), когда grep умирает из SIGPIPE.

Другой подход может заключаться в использовании xargs в качестве альтернативы -exec {} + . xargs немедленно завершается, когда порождаемая им команда умирает от сигнала, например:

 find . -type f -print0 |
   xargs -r0 grep -Hm1 --line-buffered pattern |
   head -n 5

( -r и -0 являются расширениями GNU). Как только grep выполнит запись в сломанный канал, оба grep и xargs завершат работу, а find также выйдет из себя в следующий раз. он что-то печатает после этого. Выполнение find под stdbuf -oL может ускорить это.

Версия POSIX может быть:

trap - PIPE # restore default SIGPIPE handler in case it was disabled
RE=pattern find /path -type f -exec sh -c '
  for file do
    awk '\''
      $0 ~ ENVIRON["RE"] {
        print FILENAME ": " $0
        exit
      }'\'' < "$file"
    if [ "$(kill -l "$?")" = PIPE ]; then
      kill -s PIPE "$PPID"
      exit
    fi
  done' sh {} + | head -n 5

Очень неэффективной, поскольку она запускает несколько команд для каждого файла.

5
29.04.2021, 00:07

Решение, позволяющее избежать ошибок, может быть следующим:

find / -type f -print0 \
  | xargs -0 -L 1 grep -H -m 1 --line-buffered 2>/dev/null \
  | head -10

В этом примере xargs остановится после сбоя команды, поэтому будет только одна ошибка канала, которая будет отфильтрована перенаправлением stderr.

2
29.04.2021, 00:07

Вы grep по одному файлу за раз. С помощью -quit вы останавливаете поиск при первом успешном выполнении команды grep.

[update] Моим первым решением было сразу выполнить команду grep для нескольких файлов:

find /path/ -type f -exec grep -H -m 1 'pattern' \{\} + -quit | head -n 5

(магия находится в + в конце подкоманда -exec . Добавлен -type f . Вы можете удалить параметр -H в grep , если вы уверен, что / path / содержит несколько файлов)

Проблема здесь, как сообщает @ StéphaneChazelas, заключается в том, что команда -exec выполняется асинхронно и всегда возвращает true => find завершает работу с первым файлом.

Если мы хотим, чтобы find останавливался после завершения head , find также должен получить SIGPIPE, который grep получает (signal 13). Это означает, что find должен послать что-то по конвейеру.

Вот быстрый и грязный прием, дополненный предложениями Стефана:

find /path/ -type f -exec grep -H -m 1 --line-buffered 'pattern' {} + -printf '\r' | head -n 5

С помощью -printf '\ r' я заставляю find выводить безобидный символ, который будет (надеюсь) не изменит вывод grep . Как только head остановится, find получит SIGPIPE и тоже остановится.

[update2] Я предупреждал вас, что это грязный взлом.Вот лучшее решение:

find /path/ -type f -exec grep --quiet 'pattern' {} ";" -print | head -n 5

Здесь больше не grep , который печатает имя файла, а find => больше никаких «grep завершается сигналом 13» и find останавливается на head . Проблема в том, что совпадающие строки больше не печатаются grep .

[update3] Наконец, как было предложено @Andrey, эта бесстыдная команда, приведенная ниже, решит эту последнюю проблему:

find /path/ -type f \
    -exec grep --quiet 'pattern' {} \; \
    -printf '%p:' \
    -exec grep -h -m 1 'pattern' {} \; \
| head -n 5`
1
29.04.2021, 00:07

Теги

Похожие вопросы