Как остановить цикл скрипт bash в терминале?

55

Например,

#!/bin/bash
while :
do
    sl
done

Как прекратить этот скрипт?

Yinyanghu
источник
1
Дайте больше деталей. Вы хотите остановить это интерактивно или программно?
manatwork
1
Вы можете нажать, ctrl-cчтобы отправить SIGINTсигнал (в большинстве оболочек), или вы можете нажать, ctrl-zчтобы отправить SIGTSTPсигнал (в большинстве оболочек). В случае, если вы нажали, ctrl-zсвязанный процесс не убит, а приостановлен. Вы можете возобновить его с fg(по крайней мере, в bash)
user1146332
Нет, это не работает!
Yinyanghu
4
Проблема не в сценарии, а в slкоманде, которая, на мой взгляд, является раздражающей для тех, кто пишет с орфографическими ошибками ls, показывая медленно проходящий поезд. Насколько я знаю, он ловит SIGINTсигнал и должен быть убит SIGKILL.
1
Благодарю. Не упакованный для моего дистрибутива, поэтому я не знал / нашел его. (Я думаю, что я не буду подавать запрос на это.)
manatwork

Ответы:

64

Программа slнамеренно игнорирует то SIGINT, что отправляется при нажатии Ctrl+C. Итак, во-первых, вам нужно сказать slне игнорировать SIGINT, добавив -eаргумент.

Если вы попробуете это, вы заметите, что можете остановить каждого человека sl, но они все еще повторяются. Вы должны сказать, bashчтобы выйти после того, SIGINTкак. Вы можете сделать это, поставив trap "exit" INTперед циклом.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done
Джим Пэрис
источник
5
Я не установил его для проверки, но вы также можете убить его с помощью SIGQUIT из Ctrl- \
derobert
121
  1. нажмите, Ctrl-Zчтобы приостановить сценарий
  2. kill %%

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

Вы также можете указать работу по номеру или по названию. например, когда вы приостанавливаете работу с помощью ^ Z, bash сообщит вам, каков номер его работы с чем-то вроде того [n]+ Stopped, где nвнутри квадратных скобок указан номер работы.

Для получения дополнительной информации о контроле работы и на убийство рабочих мест, бег help jobs, help fg, help bg, и help killв Баше и поиск JOB CONTROL(заглавные буквы) или jobspecна странице Баша человека.

например

$ ./killme.sh 
./killme.sh: строка 4: sl: команда не найдена
./killme.sh: строка 4: sl: команда не найдена
./killme.sh: строка 4: sl: команда не найдена
./killme.sh: строка 4: sl: команда не найдена
./killme.sh: строка 4: sl: команда не найдена
...
...
...
./killme.sh: строка 4: sl: команда не найдена
^ Z
[1] + остановлено ./killme.sh
$ kill %%
$ 
[1] + прекращено ./killme.sh

В этом примере номер задания был 1, поэтому kill %1работал бы так же, какkill %%

(ПРИМЕЧАНИЕ: я не slустановил, так что вывод - это просто «команда не найдена». В вашем случае вы получите то, что выдаст sl. Это не важно - ^Zприостановка и kill %%будет работать так же)

саз
источник
3
Еще один хороший ответ!
Yinyanghu
2
Кстати, для быстрого выполнения таких циклов ^ Z может быть более надежным способом уничтожения процесса, чем ^ C. ^ C будет отправлено в программу ( sl), выполняемую в цикле, но скрипт продолжит работу ... и запустит другой sl. Если вы нажмете ^ C несколько раз очень быстро, вы можете убить slи сценарий, и сценарий (если ни один из них не перехватит SIGINT). ^ Z приостановит выполнение сценария практически сразу (сразу, если вы не посчитаете буферизованный вывод, который все еще печатается на вашем терминале), так что вы можете убить его с помощьюkill %%
cas
Именно так! Я должен сказать, " slэто забавная программа". На этот раз мне снова весело! @ _ @
Yinyanghu
Только ответ, который, кажется, работает и тогда, когда цикл вызывается не из скрипта, а напрямую из командной строки.
Скиппи ле Гран Гуру
1
@DrewChapin Я не могу вспомнить, когда / где я узнал об этом - просто то, что я знал "с тех пор навсегда". Страница Баш человек (поиск jobspec ) говорит:The symbols %% and %+ refer to the shell's notion of the current job, which is the last job stopped while it was in the foreground or started in the background. The previous job may be referenced using %-. If there is only a single job, %+ and %- can both be used to refer to that job
Cas
7

Если вы хотите, чтобы ctrl + c остановил цикл, но не завершил скрипт, вы можете поставить || breakпосле любой команды, которую вы выполняете. Пока программа, которую вы запускаете, завершается нажатием Ctrl + C, это прекрасно работает.

#!/bin/bash
while :
do
    # ctrl+c terminates sl, but not the shell script
    sl -e || break
done

Если вы находитесь во вложенном цикле, вы можете использовать «break 2», чтобы выйти из двух уровней и т. Д.

Дейл Андерсон
источник
1
плюс 1 за перерыв 2
летающий палец
3

Вы можете завершить этот скрипт, нажав Ctrl + C на терминале, где вы запустили этот скрипт. Конечно, этот скрипт должен выполняться на переднем плане, чтобы вы могли остановить его, нажав Ctrl + C.

Или вы можете найти PID (ID процесса) этого скрипта в другом открытом терминале:

ps -ef | grep <name_of_the_script>
kill -9 <pid_of_your_running_script>

Оба способа должны сделать то, что вы просите.

panaroik
источник
1
Это не может быть прекращено с помощью Ctrl + C из терминала. Поэтому я должен убить его с помощью ps или top. Я просто хочу знать, как это убить напрямую!
Yinyanghu
3

Самый простой способ - выдать QUITсигнал, к которому обычно привязан Control-Backslash.

Когда вы увидите поезд, нажмите Control- \

RobertL
источник
1

Вы можете оболочки (Баш). Я только что попробовал, и это работает. Потому что я не вижу процесс от (работа, которую мы запускаем в скрипте цикла).killpid

ps -ef

Suwarto
источник
0

Еще один способ завершить весь сценарий - выполнить фоновую slкоманду, а затем перехватить сигнал, INTчтобы убить всю группу процессов сценария с помощью сигнала HUP.

#!/bin/bash

trap 'trap - INT; kill -s HUP -- -$$' INT
#trap 'trap - INT; kill -s HUP 0' INT

while :
do
   sl & wait
done
chanze
источник
-1

использовать set -eдля выхода из строя.

#!/bin/bash
set -e
while :
do
    sl
done
Го Чун Мао
источник
Это не сработает. slне умирает с помощью Ctrl + C.
Дункан Х Симпсон
-1
while [ true ] 
do

  #check if script is running
  ps | grep script_name.sh | grep -v grep >/dev/null 2>&1

  if [ "$!" != "0" ] ; then
    break
  else

    kill -9 ` ps -ef | grep script_name.sh | cut -d "a" -f 1` 
    echo "kill -9 `get script PID`"

  fi

done

это должно помочь.

coder007
источник
2
Как вы думаете, почему PID последней фоновой команды будет равен 0?
manatwork
-1

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

while [ something ]; do

 if [ somethingelse ]; then
   echo shut down script with exit code 0
   exit 0
 fi
done

echo something else not happend
exit 2 # Return val important for example for monitoring

Не работает. Решение = использовать Perl. пока открывает собственный баш

Rene
источник