Как я могу управлять сценарием оболочки извне, когда он находится в спящем режиме?

На самом деле вам следует использовать tac, но вы можете сделать это, используя sort -r, если вы предварите каждую строку собственным номером и отсортируете их по числам. После этого вам придется снова обрезать номера строк.

cat filename | nl | sort -n -r | cut -f 2-

Это не будет работать для всех входных данных.:nlбудет пропускать пустые строки, а также искать «разделы», разделенные строками, содержащими только (кратные )строки \:. Вам нужно будет использовать -baдля обработки пустых строк и изменить разделитель разделов с помощью -d XZна любую последовательность из 2 -символов, которая не появляется одна в строке.

16
08.02.2021, 11:54
4 ответа

За управление синхронизацией отвечает сценарий. Даже если это означает использование /bin/sleepсегодня, это может не произойти в будущем, так что убийство, которое на самом деле не гарантирует работу -в долгосрочной перспективе. Что ж, я думаю, вы можете дать такую ​​гарантию, но лучше этого не делать. Я хочу сказать, что вы не должны убивать сон напрямую из-за пределов скрипта, поскольку сон — это деталь реализации. Вместо этого пусть ваш сценарий перехватывает другой сигнал, например SIGUSR1, и отправляет его вашему сценарию.

Простой пример может выглядеть так:

#!/usr/bin/env bash

kill_the_sleeper () {
    # This probably isn't really needed here
    # If we don't kill the sleep process, it'll just
    # hang around in the background until it finishes on its own
    # which isn't much of an issue for "sleep" in particular
    # But cleaning up after ourselves is good practice, so let's
    # Just in case we end up doing something more complicated in future
    if [ -v sleep_pid ]; then
        kill "$sleep_pid"
    fi
}

trap kill_the_sleeper USR1 EXIT

while true; do
    # Signals don't interrupt foreground jobs,
    # but they do interrupt "wait"
    # so we "sleep" as a background job
    sleep 5m &
    # We remember its PID so we can clean it up
    sleep_pid="$!"
    # Wait for the sleep to finish or someone to interrupt us
    wait
    # At this point, the sleep process is dead (either it finished, or we killed it)
    unset sleep_pid

    # PART X: code that executes every 5 mins
done

Затем вы можете запустить ЧАСТЬ X , запустив kill -USR1 "$pid_of_the_script"илиpkill -USR1 -f my_fancy_script

Этот сценарий не совершенен в любом случае, но, по крайней мере, для простых случаев он должен подойти.

21
18.03.2021, 22:31

Мне нравится метод использования @sitaram ionotifywait. Однако то же самое можно сделать, используя более распространенную инфраструктуру -, команду оболочки read, команду (, которая может использовать необязательный тайм-аут в Bash/ksh/Zsh )и FIFO.

Цикл ожидания -выглядит примерно так:

mkfifo /tmp/myfifo
while true; do
    read -t $((5*60)) <> /tmp/myfifo
    date
    echo "Executed every 5 minutes"
done

и чтение прерывается досрочно, просто записывая новую строку в FIFO:

echo > /tmp/myfifo

Пара замечаний:

  1. Вместо обычного <используется не-блокирующее перенаправление <>. Обычное перенаправление будет блокироваться в Bash(до тех пор, пока FIFO не будет записано в ), до того, как Bash когда-либо запустит read, и поэтому никогда не будет тайм-аута, если FIFO никогда не записывался.
  2. while [ true ]означает проверить, не является ли строка «true» -пустой, и продолжить цикл while, если она не -пуста. Однако while trueозначает запуск команды true(, которая, как вы, вероятно, догадались, )всегда возвращает истину, и продолжает цикл while, если она истинна. В этом случае результат точно такой же. Однако я думаю, что без тестовой конструкции [ ]будет понятнее. Рассмотрим while [ false ]против while false...
  3. $((5*60))является арифметическим расширением. 300можно было бы так же легко использовать, но это помогает продемонстрировать, как легко можно выполнять арифметические действия в командных строках.
8
18.03.2021, 22:31

В другом терминале
Убить процесс sleep:

pkill -f "sleep 5m"

Цикл продолжится.


Если pkillнедоступен в вашей ОС, вы можете получить PID, используя:

$ ps aux | grep '[s]leep'
username 14628  0.0  0.0   8816   672 pts/19   S+   08:33   0:00 sleep 5m

Затем запустите kill PID, чтобы завершить процесс (здесь:kill 14628).


Это хорошо для ручного уничтожения вашего sleep, но это может быть не очень хорошим решением для общих целей в сценариях, так как оно уничтожит все процессы с sleep 5mв любом месте команды.


Более безопасная альтернатива, если вы можете редактировать скрипт:

Измените свой скрипт для записи PID в файл:

TMP_DIR="$HOME/.cache/myscript/"
mkdir -p "$TMP_DIR"
while [ true ]
do
  sleep 5m &
  printf '%s' $! > "$TMP_DIR"/sleep.PID
  wait
  # PART X: code that executes every 5 mins
done

Тогда можно бежать:

kill $(< ~/.cache/myscript/sleep.PID)

Обратите внимание, что ваш PID-файл может быть перезаписан, например. другим экземпляром того же скрипта и может работать недостаточно надежно для ваших требований.

13
18.03.2021, 22:31

Если у вас есть доступный inotifywait, вы можете настроить сигнальный файл (как пустой файл с уникальным именем )и использовать inotifywait.

Т.е. заменить сон этим:

touch $HOME/.cache/sentinel
inotifywait -t 300 $HOME/.cache/sentinel

Если вы хотите инициировать это для немедленного выполнения «части X», просто touch $HOME/.cache/sentinelс другого терминала.

4
18.03.2021, 22:31

Теги

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