Это находится в SUSv3 (Posix, 2001), но не в SUSv2 (искажают Unix98).
У гну 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).
Этот подобный вопрос имеет еще несколько опций: Как представить тайм-аут для сценариев оболочки?
Это должно работать:
tail -f /var/log/whatever.log > ten_second_sample & sleep 10 && kill $!
Запуск tail
в фоне и параллельно sleep
10 секунд и после этого kill
$!
который является PID последнего запущенного фонового процесса.
Использование уничтожения 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
.