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

35

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

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

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

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

Рори
источник
6
Ответ Денниса верен, но если вы этого не сделали, вам не нужно «нажимать на него, как на сумасшедшего», просто держите его и позвольте клавиатуре повторить его :-)
Кайл Брандт
Я всегда просто удерживаю Cntl-C, в целом работает нормально.
Скотт Алан Миллер

Ответы:

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

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

Kenster
источник
4
Дополнительный совет: если вы находитесь во вложенном цикле и хотите полностью завершить, используйте break 2(или замените «2» на количество вложенных циклов, которое вы хотите завершить).
Долан Антенуччи
26

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

trap "echo Exited!; exit;" SIGINT SIGTERM

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

Ян Гринлиф Янг
источник
Спасибо, это общее решение, которое сработало для меня
wi1
25

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

trap <command> SIGINT

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

Приостановлено до дальнейшего уведомления.
источник
7
  1. Нажмите, Ctrl-Zчтобы приостановить сценарий;
  2. kill %%

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

Скиппи ле Гран Гуру
источник
Это здорово, потому что работает «постфактум», когда вы хотите прервать длительный цикл, который вы уже запустили.
Ник Маттео
лучший ответ, спасибо!
Костанос
6

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

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

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

rsync -a * example.com:somewhere/
amphetamachine
источник
0

Я склонен помещать в свой цикл другую команду, которая может быть легко прервана. Это требует двух 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.

Алан Портер
источник