Назад | Перейти на главную страницу

Bash Loop - Как остановить цикл, когда я нажимаю Control-C внутри команды?

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

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done

Однако, если я хочу все это остановить, я нажимаю Control-C. Это останавливает rsync, но затем продолжает переход к следующему. В этом случае я понимаю, что произошло, а затем просто нажимаю Control-C, как сумасшедший, пока все не заработает снова.

Есть ли способ «исправить» это. Я хочу, чтобы если у меня был такой цикл, и я нажму Control-C, он вернет меня в мою оболочку bash.

for DIR in * ; do rsync -a $DIR example.com:somewhere/ || break; done

Это также приведет к выходу из цикла, если по какой-то причине отдельный запуск rsync завершится неудачно.

Чтобы расширить ответ Денниса, ваш код может выглядеть так:

trap "echo Exited!; exit;" SIGINT SIGTERM

В качестве рабочего примера (который включает rsync) ознакомьтесь с http://gist.github.com/279849.

Вы можете установить ловушку для Control-C.

trap <command> SIGINT

выполнит command при нажатии Control-C. Просто положите trap утверждение где-нибудь в вашем сценарии в том месте, где вы хотите, чтобы он стал эффективным.

  1. Нажмите Ctrl-Z приостановить скрипт;
  2. kill %%

Авторы, объяснения и более подробная информация в этот ответ.

Когда вы помещаете строку команд в круглые скобки, строка будет действовать как единый процесс, получит SIGINT и завершится, когда вы нажмете Ctrl-C:

(for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done)

Но! В случае rsync команда, она допускает использование нескольких источников, поэтому написанный вами код лучше записать как:

rsync -a * example.com:somewhere/

Я стараюсь добавить в свой цикл еще одну команду, которую можно легко прервать. Для этого нужно нажать два Ctrl-C.

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; sleep 1 ; done

Это не такое уж хорошее решение для этого rsync, который вы, вероятно, захотите запустить быстро. Но он хорошо работает для других циклов, например этого:

while true ; do ping -c 10 example.com ; sleep 1 ; done

Этот цикл будет повторно искать адрес example.com каждый раз в цикле, что полезно, если вы следите за изменением DNS.