Считайте данные с канала для определенного количества времени (в секундах)

Это находится в SUSv3 (Posix, 2001), но не в SUSv2 (искажают Unix98).

4
27.03.2013, 18:37
3 ответа

У гну coreutils начиная с версии 7.0 есть a timeout команда:

timeout 10 tail -f /var/log/whatever.log 

Если Вы действительно нуждаетесь в канале к тайм-ауту для некоторой немного отличающейся процедуры, то передаете по каналу в timeout:

tail -f /var/log/whatever.log | timeout 10 cat > ./10_second_sample_of_log

Отметьте, хотя то уничтожение некоторой произвольной части конвейера может вызвать проблемы из-за буферизации, в зависимости от сигналов и поведения программы (этот вопрос связанные с покрытиями проблемы: Выключите буферизацию в канале). Это будет обычно изменять код выхода процесса также.

Если Вы не имеете (недавнее) coreutils, эта простая программа тайм-аута также работает хорошо http://www.unixlabplus.com/unix-prog/timeout/timeout.html или подход жемчуга:

tail -f /var/log/whatever.log | perl -n -e 'BEGIN{alarm 10; $|=1}; print;'

(Отметьте $|=1 выключает выходную буферизацию, это должно предотвратить потерю вывода в конвейере, как упомянуто выше.)

(Немного древний) пакет Netpipes также имеет a timelimit команда (который можно все еще найти в некоторых системах Linux).

Этот подобный вопрос имеет еще несколько опций: Как представить тайм-аут для сценариев оболочки?

6
27.01.2020, 20:48

Это должно работать:

tail -f /var/log/whatever.log > ten_second_sample & sleep 10 && kill $!

Запуск tail в фоне и параллельно sleep 10 секунд и после этого kill $! который является PID последнего запущенного фонового процесса.

4
27.01.2020, 20:48

Использование уничтожения PID может быть ненадежным, если tail -f завершается слишком рано (например, файл не существует). Еще одно более общее решение, которое также остановит «таймер уничтожения», если оно будет выполнено до истечения времени ожидания, - это использовать wait и kill %% ( %% указывает на самое последнее задание, запущенное bash - с использованием и ).

Конструкция будет выглядеть так (в которой sleep 2 - любая пользовательская команда с параметрами и т. Д., А таймаут установлен на 10 секунд):

# Your command that may take some (or not) time to execute:
sleep 2 &
# Set a timer that kills the last started job
sleep 10 & wait -n 1; kill %%; wait -n 1

Эта конструкция будет ждать, пока не будет достигнут тайм-аут , или пользовательская команда завершена (в этом случае sleep 2 всегда останавливается первым). Тогда, соответственно, команда или тайм-аут будут уничтожены с помощью kill %% . Затем последний wait -n 1 блокирует дальнейшее выполнение до тех пор, пока команда или тайм-аут не будут фактически уничтожены (это необязательно, но, вероятно, желательно).

Примечание. Более ранние команды, выполняемые параллельно, не будут затронуты, как это требуется и ожидается.

Пример

Более практичный пример с чтением строки из именованного канала с тайм-аутом, но для которого нельзя использовать флаг тайм-аута read :

# Custom bash function to set timeout in seconds for the most recently started job (parallel execution).
timeout() { sleep $1 & wait -n 1; kill %%; wait -n 1 }

# Example 1:
mkfifo /tmp/test
read ln </tmp/test &
timeout 10

Потому что в него ничего не записано / tmp / test время ожидания истечет через 10 секунд. Чтобы показать, что даже когда команда завершается немедленно, она останавливает таймер уничтожения:

# Example 2:
mkfifo /tmp/test
echo "Hello" >/tmp/test &
ln="$(read ln </tmp/test && echo -e "$ln" & timeout 10)"
echo "Line was read: $ln"

Примечание относительно практического использования именованного канала.Поскольку read ln выполняется в подоболочке, к нему нельзя получить доступ в (родительском) скрипте. Поэтому в строке печатается echo , чтобы сохранить ее в (другой) переменной ln .

0
27.01.2020, 20:48

Теги

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