394

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

В настоящее время я использую это:

while read; do ./myfile.py ; done

И затем мне нужно перейти к этому терминалу и нажать Enter, всякий раз, когда я сохраняю этот файл в моем редакторе. Я хочу что-то вроде этого:

while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done

Или любое другое простое решение.

Кстати: я использую Vim и знаю, что могу добавить автокоманду для запуска чего-либо на BufWrite, но это не то решение, которое мне сейчас нужно.

Обновление: я хочу что-то простое, если возможно, отказаться. Более того, я хочу, чтобы что-то запускалось в терминале, потому что я хочу видеть вывод программы (я хочу видеть сообщения об ошибках).

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

34 ответа34

375

Просто, используя inotifywait (установите пакет inotify-tools вашего дистрибутива):

while inotifywait -e close_write myfile.py; do ./myfile.py; done

или же

inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
  ./myfile.py         # or "./$filename"
done

Первый фрагмент проще, но у него есть существенный недостаток: он пропустит изменения, выполненные, когда inotifywait не работает (в частности, когда работает myfile ). Второй фрагмент не имеет этого дефекта. Однако следует помнить, что предполагается, что имя файла не содержит пробелов. Если это проблема, используйте параметр --format чтобы изменить вывод, не включая имя файла:

inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
  ./myfile.py
done

В любом случае, есть ограничение: если какая-то программа заменит myfile.py другим файлом, а не записывает в существующий myfile , inotifywait умрет. Многие редакторы работают таким образом.

Чтобы преодолеть это ограничение, используйте inotifywait в каталоге:

inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
  if [ "$filename" = "myfile.py" ]; then
    ./myfile.py
  fi
done

В качестве альтернативы, используйте другой инструмент, который использует те же базовые функции, например, incron (позволяет регистрировать события при изменении файла) или fswatch (инструмент, который также работает во многих других вариантах Unix, используя аналог каждого варианта inotify Linux).

133

entr (http://entrproject.org/) предоставляет более дружественный интерфейс для inotify (а также поддерживает * BSD и Mac OS X).

Это позволяет очень легко указать несколько файлов для просмотра (ограничено только ulimit -n), избавляет от необходимости иметь дело с заменяемыми файлами и требует меньше синтаксиса bash:

$ find . -name '*.py' | entr ./myfile.py

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

Флаги типа -c (очистка экрана между запусками) и -d (выход при добавлении нового файла в контролируемый каталог) добавляют еще больше гибкости, например, вы можете сделать:

$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done

По состоянию на начало 2018 года он все еще находится в активной разработке, и его можно найти в Debian & Ubuntu (apt install entr); Строительство из репо автора было в любом случае безболезненным.

103

Я написал программу на Python, чтобы сделать именно это, когда это изменилось.

Использование простое:

when-changed FILE COMMAND...

Или посмотреть несколько файлов:

when-changed FILE [FILE ...] -c COMMAND

FILE может быть каталогом. Смотреть рекурсивно с -r . Используйте %f для передачи имени файла команде.

47

Как насчет этого сценария? Он использует команду stat для получения времени доступа к файлу и запускает команду всякий раз, когда происходит изменение времени доступа (при каждом обращении к файлу).

#!/bin/bash

### Set initial time of file
LTIME=`stat -c %Z /path/to/the/file.txt`

while true    
do
   ATIME=`stat -c %Z /path/to/the/file.txt`

   if [[ "$ATIME" != "$LTIME" ]]
   then    
       echo "RUN COMMAND"
       LTIME=$ATIME
   fi
   sleep 5
done
30

Решение с использованием Vim:

:au BufWritePost myfile.py :silent !./myfile.py

Но я не хочу, чтобы это решение, потому что это немного раздражает, печатать, немного сложно вспомнить, что именно печатать, и немного сложно отменить его эффекты (нужно запустить :au! BufWritePost myfile.py). Кроме того, это решение блокирует Vim до тех пор, пока команда не завершит выполнение.

Я добавил это решение просто для полноты, так как оно может помочь другим людям.

Чтобы отобразить вывод программы (и полностью прервать процесс редактирования, поскольку вывод будет записываться в ваш редактор в течение нескольких секунд, пока вы не нажмете Enter), удалите команду :silent .

23

Если у вас установлен npm , возможно, nodemon - это самый простой способ начать работу, особенно в OS X, которая, очевидно, не имеет инструментов inotify. Он поддерживает запуск команды при изменении папки.

14

rerun2 (на github) - это 10-строчный Bash-скрипт вида:

#!/usr/bin/env bash

function execute() {
    clear
    echo "$@"
    eval "$@"
}

execute "$@"

inotifywait --quiet --recursive --monitor --event modify --format "%w%f" . \
| while read change; do
    execute "$@"
done

Сохраните версию github как 'rerun' в вашей переменной PATH и вызовите ее, используя:

rerun COMMAND

Он запускает COMMAND каждый раз, когда в вашем текущем каталоге происходит событие изменения файловой системы (рекурсивно.)

Вещи, которые могут понравиться об этом:

  • Он использует inotify, поэтому более отзывчив, чем опрос. Потрясающе для запуска модульных тестов с точностью до миллисекунды или рендеринга файлов графических точек каждый раз, когда вы нажимаете «сохранить».
  • Поскольку это так быстро, вам не нужно беспокоиться о том, чтобы игнорировать большие подкаталоги (например, node_modules) только из соображений производительности.
  • Это очень супер-отзывчивый, потому что он вызывает inotifywait только один раз, при запуске, вместо того, чтобы запускать его и нести дорогостоящий удар по созданию часов на каждой итерации.
  • Это всего лишь 12 строк Bash
  • Поскольку это Bash, он интерпретирует команды, которые вы передаете, точно так же, как если бы вы вводили их в приглашении Bash. (Предположительно это менее круто, если вы используете другую оболочку.)
  • Он не теряет события, которые происходят во время выполнения COMMAND, в отличие от большинства других решений inotify на этой странице.
  • При первом событии он вводит «мертвый период» на 0,15 секунды, в течение которого другие события игнорируются, прежде чем COMMAND будет выполнен ровно один раз. Это происходит из-за того, что поток событий, вызванный танцем create-write-move, который Vi или Emacs делает при сохранении буфера, не вызывает много трудоемких выполнений, возможно, медленного набора тестов. Любые события, которые затем происходят во время выполнения COMMAND, не игнорируются - они вызовут второй период простоя и последующее выполнение.

Вещи, которые могут не понравиться об этом:

  • Он использует inotify, поэтому не будет работать за пределами Linuxland.
  • Поскольку он использует inotify, он будет пытаться просмотреть каталоги, содержащие больше файлов, чем максимальное количество пользовательских наблюдений inotify. По умолчанию на разных компьютерах, которые я использую, установлено, что оно составляет от 5000 до 8000, но его легко увеличить. См. Https://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached
  • Не удается выполнить команды, содержащие псевдонимы Bash. Я могу поклясться, что раньше это работало. В принципе, потому что это Bash, не выполняющий команду COMMAND в подоболочке, я ожидал, что это сработает. Я хотел бы услышать, если кто-нибудь знает, почему это не так. Многие другие решения на этой странице также не могут выполнять такие команды.
  • Лично мне хотелось бы нажать клавишу в терминале, в котором он работает, чтобы вручную вызвать дополнительное выполнение команды. Могу ли я добавить это как-нибудь, просто? Параллельно работающий цикл while read -n1, который также вызывает execute?
  • Прямо сейчас я кодировал его, чтобы очистить терминал и печатать выполненную КОМАНДУ на каждой итерации. Некоторые люди могут захотеть добавить флаги командной строки, чтобы отключить подобные вещи и т.д. Но это увеличит размер и сложность во много раз.

Это уточнение ответа @ cychoi.

12

Вот простой сценарий оболочки Bourne, который:

  1. Принимает два аргумента: файл для мониторинга и команду (с аргументами, если необходимо)
  2. Копирует файл, который вы отслеживаете, в каталог /tmp
  3. Проверяет каждые две секунды, чтобы увидеть, является ли файл, который вы отслеживаете, более новым, чем копия
  4. Если он новее, он перезаписывает копию новым оригиналом и выполняет команду
  5. Убирает за собой при нажатии Ctr-C

    #!/bin/sh  
    f=$1  
    shift  
    cmd=$*  
    tmpf="`mktemp /tmp/onchange.XXXXX`"  
    cp "$f" "$tmpf"  
    trap "rm $tmpf; exit 1" 2  
    while : ; do  
        if [ "$f" -nt "$tmpf" ]; then  
            cp "$f" "$tmpf"  
            $cmd  
        fi  
        sleep 2  
    done  
    

Это работает на FreeBSD. Единственная проблема переносимости, о которой я могу подумать, это то, что в некоторых других Unix нет команды mktemp(1), но в этом случае вы можете просто жестко закодировать имя временного файла.

10

Для тех, кто не может установить inotify-tools как я, это должно быть полезно:

watch -d -t -g ls -lR

Эта команда завершится при изменении выходных данных, ls -lR выведет список всех файлов и каталогов с указанием их размера и дат, поэтому, если файл будет изменен, он должен выйти из команды, как говорит man:

-g, --chgexit
          Exit when the output of command changes.

Я знаю, что этот ответ не может быть прочитан кем-либо, но я надеюсь, что кто-то достигнет его.

Пример командной строки:

~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"

Откройте другой терминал:

~ $ echo "testing" > /tmp/test

Теперь первый терминал выведет 1,2,3

Пример простого скрипта:

#!/bin/bash
DIR_TO_WATCH=${1}
COMMAND=${2}

watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
8

Посмотрите на Incron. Это похоже на cron, но использует события inotify вместо времени.

6

Другое решение с NodeJs, fsmonitor :

  1. устанавливать

    sudo npm install -g fsmonitor
    
  2. Из командной строки (например, монитор журналов и "розничная торговля", если один файл журнала изменяется)

    fsmonitor -s -p '+*.log' sh -c "clear; tail -q *.log"
    
6

Под Linux:

man watch

watch -n 2 your_command_to_run

Будет запускать команду каждые 2 секунды.

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

5

если у вас установлен nodemon , то вы можете сделать это:

nodemon -w <watch directory> -x "<shell command>" -e ".html"

В моем случае я редактирую html локально и отправляю его на мой удаленный сервер при изменении файла.

nodemon -w <watch directory> -x "scp filename jaym@jay-remote.com:/var/www" -e ".html"
5

Посмотрите на Guard, в частности, с этим плагином:

https://github.com/hawx/guard-shell

Вы можете настроить его на просмотр любого количества шаблонов в каталоге вашего проекта и выполнение команд при возникновении изменений. Хороший шанс, даже если есть плагин для того, что вы пытаетесь сделать в первую очередь.

5

Watchdog - это проект Python, и он может быть именно тем, что вы ищете:

Поддерживаемые платформы

  • Linux 2.6 (inotify)
  • Mac OS X (FSEvents, kqueue)
  • FreeBSD/BSD (kqueue)
  • Windows (ReadDirectoryChangesW с портами завершения ввода / вывода; рабочие потоки ReadDirectoryChangesW)
  • Независимый от ОС (опрос диска на наличие снимков каталогов и их периодическое сравнение; медленный и не рекомендуется)

Просто написал оболочку командной строки для него watchdog_exec:

Пример работает

В случае события fs, включающего файлы и папки в текущем каталоге, выполните команду echo $src $dst , если только событие fs не изменено, а затем выполните команду python $src .

python -m watchdog_exec . --execute echo --modified python

Использование коротких аргументов и ограничение на выполнение только тогда, когда в событиях используется « main.py»:

python -m watchdog_exec . -e echo -a echo -s __main__.py

РЕДАКТИРОВАТЬ: Только что обнаружил, что Watchdog имеет официальный CLI под названием watchmedo , так что проверьте это также.

4

Если ваша программа генерирует какой-либо журнал / вывод, вы можете создать Makefile с правилом для этого журнала / вывода, который зависит от вашего сценария и сделать что-то вроде

while true; do make -s my_target; sleep 1; done

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

4

Улучшено после ответа Жиля.

Эта версия запускает inotifywait один раз и отслеживает события (.eg: modify) после этого. Таким образом, inotifywait не нужно повторно выполнять при каждом обнаруженном событии.

Это быстро и быстро! (даже при рекурсивном мониторинге большого каталога)

inotifywait --quiet --monitor --event modify FILE | while read; do
    # trim the trailing space from inotifywait output
    REPLY=${REPLY% }
    filename=${REPLY%% *}
    # do whatever you want with the $filename
done
3

Еще немного о программировании, но вы хотите что-то вроде inotify. Существуют реализации на многих языках, таких как jnotify и pyinotify.

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

3

Мне нравится простота while inotifywait ...; do ...; done однако, у него есть две проблемы:

  • Изменения файлов, происходящие во время do ...; будет пропущено
  • Медленно при использовании в рекурсивном режиме

Для этого я создал вспомогательный скрипт, который использует inotifywait без этих ограничений: inotifyexec

Я предлагаю вам поставить этот скрипт на вашем пути, как в ~/bin/ . Использование описывается просто запуском команды.

Пример: inotifyexec "echo test" -r .

3

Улучшено решение Себастьяна с помощью команды watch :

watch_cmd.sh:

#!/bin/bash
WATCH_COMMAND=${1}
COMMAND=${2}

while true; do
  watch -d -g "${WATCH_COMMAND}"
  ${COMMAND}
  sleep 1     # to allow break script by Ctrl+c
done

Пример звонка:

watch_cmd.sh "ls -lR /etc/nginx | grep .conf$" "sudo service nginx reload"

Это работает, но будьте осторожны: команда watch имеет известные ошибки (см. Man): она реагирует на изменения только в VISIBLE в терминальных частях вывода -g CMD .

3

Для тех из вас, кто ищет решение FreeBSD, вот порт:

/usr/ports/sysutils/wait_on
2

Вы можете попробовать рефлекс.

Reflex - небольшой инструмент для просмотра каталога и повторного запуска команды при изменении определенных файлов. Он отлично подходит для автоматического запуска задач компиляции /lint /test и для перезагрузки приложения при изменении кода.

# Rerun make whenever a .c file changes
reflex -r '\.c$' make
1

Для тех, кто использует OS X, вы можете использовать LaunchAgent, чтобы посмотреть путь / файл на предмет изменений и что-то сделать, когда это произойдет. К вашему сведению - LaunchControl - хорошее приложение для простого создания / изменения / удаления демонов / агентов.

(пример взят здесь)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>
        <string>say</string>
        <string>yy</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>~/Desktop/</string>
    </array>
</dict>
</plist>
1

У меня есть GIST для этого, и использование довольно просто

watchfiles <cmd> <paths...>

https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55

1

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

#!/bin/bash
MONDIR=$(dirname $1)
ARQ=$(basename $1)

inotifywait -mr -e close_write $MONDIR | while read base event file 
do
  if (echo $file |grep -i "$ARQ") ; then
    $1
  fi
done

Сохраните это как runatwrite.sh

Usage: runatwrite.sh myfile.sh

он будет запускать myfile.sh при каждой записи.

1

Ответ oneliner, который я использую, чтобы отслеживать изменения файла:

$ while true ; do NX=`stat -c %Z file` ; [[ $BF != $NX ]] && date >> ~/tmp/fchg && BF=$NX || sleep 2 ; done

Вам не нужно инициализировать BF, если вы знаете, что первая дата является временем начала.

Это просто и портативно. Здесь есть другой ответ, основанный на той же стратегии с использованием сценария. Посмотрите также.


Использование: Я использую это для отладки и ~/.kde/share/config/plasma-desktop-appletsrc ; что по неизвестной причине продолжает терять мой SwitchTabsOnHover=false

0

Основное использование

Вот решение, которое не требует установки большего количества программного обеспечения и работает из коробки.

tail -q --follow=name myfile.txt | head -n 0

Эта команда завершается при следующих условиях:

  • Строка добавляется в myfile.txt после запуска команды
  • myfile.txt заменяется другим после запуска команды

Вы говорите, что используете vim, и vim заменит файл при сохранении. Я проверил это работает с Vim.

Вы можете игнорировать вывод этой команды, она может упомянуть что-то вроде:

tail: «myfile.txt» заменен; следующий конец нового файла

Расширенное использование

Вы можете объединить это с timeout чтобы вернуть true или false. Вы можете использовать это так:

timeout 5s bash -c 'tail -q --follow = имя канала 2> /dev /null | голова -n 0 '&& echo изменена || тайм-аут эха

обсуждение

tail использует inotify под капотом. Вот так вы получаете это причудливое асинхронное поведение без опроса. Вероятно, есть какая-то другая стандартная Unix-программа, использующая inotify которую мы можем использовать более элегантно.

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

На RHEL я могу использовать:

тайм-аут 5s SH-C 'GIO монитор трубы | голова -n 0 '&& echo изменена || тайм-аут эха

Но я не уверен, что это портативно.

0

find может сделать свое дело.

while true; do
    find /path/to/watched/file -ctime 1s | xargs do-what-you-will
done

find -ctime 1s печатает имя файла, если оно было изменено за последние 1s .

0

Инструмент «Fido» может быть еще одним вариантом для этой необходимости. Смотрите https://www.joedog.org/fido-home/

0

Для людей, которые находят это в Google для изменений в конкретном файле, ответ гораздо проще (вдохновленный ответом Жиля).

Если вы хотите сделать что-то после того, как был записан определенный файл, вот как:

while true; do
  inotifywait -e modify /path/to/file
  # Do something *after* a write occurs, e.g. copy the file
  /bin/cp /path/to/file /new/path
done

Сохраните это как, например, copy_myfile.sh и поместите файл .sh в папку /etc/init.d/ чтобы запустить его при запуске.

0

Как и некоторые другие, я также написал для этого облегченный инструмент командной строки. Он полностью документирован, протестирован и модульный.

Часы-Do

Монтаж

Вы можете установить его (если у вас есть Python3 и pip), используя:

pip3 install git+https://github.com/vimist/watch-do

использование

Используйте это сразу, запустив:

watch-do -w my_file -d 'echo %f changed'

Обзор возможностей

  • Поддерживает глобализацию файлов (используйте -w '*.py' или -w '**/*.py')
  • Запустите несколько команд для изменения файла (просто снова укажите флаг -d)
  • Динамически поддерживает список файлов для просмотра, если используется globbing (-r чтобы включить это)
  • Несколько способов "посмотреть" файл:
    • Время модификации (по умолчанию)
    • Файловый хеш
    • Тривиально реализовать свой собственный (это наблюдатель ModificationTime)
  • Модульная конструкция. Если вы хотите, чтобы команды выполнялись, когда к файлу обращаются, написать свой собственный наблюдатель (механизм, который определяет, должны ли исполнители выполняться), тривиально.
0

Я написал программу на Python для этого, называемую rerun.

ОБНОВЛЕНИЕ: Этот ответ представляет собой скрипт Python, который запрашивает изменения, что полезно в некоторых случаях. Для сценария Bash только для Linux, который использует inotify, см. Мой другой ответ, поищите на этой странице «rerun2».

Установите для Python2 или Python3 с:

pip install --user rerun

и использование очень просто:

rerun "COMMAND"

Команда ожидается как один аргумент, а не как последовательность аргументов, разделенных пробелом. Следовательно, процитируйте это, как показано, что уменьшает любые дополнительные побеги, которые вам нужно добавить. Просто введите команду так, как вы бы ввели ее в командной строке, но в кавычках.

По умолчанию он просматривает все файлы в текущем каталоге или под ним, пропуская такие вещи, как известные каталоги управления исходным кодом, .git, .svn и т.д.

Необязательные флаги включают '-i NAME', который игнорирует изменения именованных файлов или каталогов. Это может быть дано несколько раз.

Поскольку это скрипт Python, он должен запускать команду как подпроцесс, и мы используем новый экземпляр текущей оболочки пользователя для интерпретации «КОМАНДЫ» и решения, какой процесс на самом деле запустить. Однако, если ваша команда содержит псевдонимы оболочки и т.п., которые определены в .bashrc, они не будут загружены подоболочкой. Чтобы это исправить, вы можете повторно установить флаг '-I', чтобы использовать интерактивные (иначе называемые 'логин') субоболочки. Это медленнее и более подвержено ошибкам, чем запуск обычной оболочки, потому что она должна быть источником вашего .bashrc.

Я использую его с Python 3, но последний раз, когда я проверял, повторный запуск все еще работал с Python 2.

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

С другой стороны, опрос означает, что задержка составляет от 0,0 до 1,0 секунды, и, конечно, медленнее отслеживать очень большие каталоги. Сказав это, я никогда не сталкивался с настолько большим проектом, что это даже заметно, если вы используете '-i', чтобы игнорировать такие важные вещи, как ваши virtualenv и node_modules.

Хммм. rerun был для меня незаменим в течение многих лет - я в основном использую его по восемь часов каждый день для запуска тестов, восстановления точечных файлов при их редактировании и т. д. Но теперь я пришел, чтобы напечатать это здесь, ясно, что мне нужно перейти на Решение, которое использует inotify (я больше не использую Windows или OSX.) и написано на Bash (поэтому оно работает с псевдонимами без каких-либо дополнительных действий).

0

Описание

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

Пример использования

watch_file my_file.php php my_file.php

Эта строка будет смотреть php-файл my_file.php и запускаться через интерпретатор php всякий раз, когда он изменяется.


Определение функции

function watch_file (){

### Set initial time of file
LTIME=`stat -c %Z $1`
printf "\033c"
echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
${@:2}

while true
do
   ATIME=`stat -c %Z $1`

   if [[ "$ATIME" != "$LTIME" ]]
   then
    printf "\033c"
    echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
    ${@:2}
    LTIME=$ATIME
   fi
   sleep 1
done
}

кредит

Это в основном более общий вариант ответа VDR.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .