it-swarm-eu.dev

Ukončení nekonečné smyčky

Mám příkaz, který chci znovu automaticky spustit pokaždé, když skončí, takže jsem spustil něco podobného:

while [ 1 ]; do COMMAND; done;

ale pokud nedokážu zastavit smyčku Ctrl-c protože to zabíjí COMMAND a ne celou smyčku.

Jak bych dosáhl něčeho podobného, ​​ale co mohu zastavit, aniž bych musel terminál uzavřít?

57
howardh

Zkontrolujte stav ukončení příkazu. Pokud byl příkaz ukončen signálem, bude výstupní kód 128 + číslo signálu. Z GNU online dokumentace pro bash :

Pro účely prostředí Shell byl úspěšný příkaz, který opouští stav nulového ukončení. Nenulový stav ukončení označuje selhání. Toto zdánlivě kontraintuitivní schéma se používá, takže existuje jeden dobře definovaný způsob, jak označit úspěch, a různé způsoby, jak označit různé režimy selhání. Když příkaz skončí na fatálním signálu, jehož číslo je N, použije Bash jako stav ukončení hodnotu 128 + N.

POSIX také specifikuje , že hodnota příkazu ukončeného signálem je větší než 128, ale nezdá se, že by specifikovala jeho přesnou hodnotu jako GNU dělá:

Stav výstupu příkazu, který byl ukončen, protože přijal signál, musí být hlášen jako větší než 128.

Například pokud přerušíte příkaz s control-C, bude výstupní kód 130, protože SIGINT je signálem 2 v unixových systémech. Tak:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done
40
Kyle Jones

Během práce můžete práci zastavit a umístit ji na pozadí ctrl+z. Pak můžete svou práci zabít:

$ kill %1

Kde [1] je vaše pracovní číslo.

51
Jem

Řekl bych, že by bylo nejlepší vložit nekonečnou smyčku do skriptu a zpracovat tam signály. Zde je základní výchozí bod. Určitě budete chtít upravit tak, aby vyhovovaly. Skript používá k zachycení trap ctrl-c (nebo SIGTERM), zabije příkaz (zde jsem použil sleep jako test) a skončí.

cleanup ()
{
kill -s SIGTERM $!
exit 0
}

trap cleanup SIGINT SIGTERM

while [ 1 ]
do
    sleep 60 &
    wait $!
done
21
ephsmith

Obecně jen podržím Ctrl-C. Dříve nebo později se zaregistruje mezi COMMAND a tím ukončí smyčku while. Možná existuje lepší způsob.

15
jw013

Proč ne jednoduše,

while [ 1 ]; do COMMAND || break; done;

Nebo při použití ve skriptu

#!/bin/bash
while [ 1 ]; do
  # ctrl+c terminates COMMAND and exits the while loop
  # (assuming COMMAND responds to ctrl+c)
  COMMAND || break
done;
10
Dale Anderson

Pokud spustíte bash s -e ukončí se za všech chybových podmínek:

#!/bin/bash -e
false # returns 1
echo This won't be printed
9
Brendan Long

Dávám přednost jinému řešení:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done

Chcete-li zabít smyčku, stačí:

rm .runcmd && kill `pidof COMMAND`
3
M4tze
  1. Proces můžete vždy zabít pomocí jeho PID, není třeba uzavírat váš terminál
  2. Pokud chcete spouštět něco v nekonečné smyčce jako démon, měli byste to dát do pozadí
  3. while : vytvoří nekonečnou smyčku a ušetří vám psaní [ 1 ]

    while :; do COMMAND; done &
    

Tím se vytiskne PID. Pokud ukončíte výzvu pomocí ctrl+d pak se úloha na pozadí neukončí a později ji můžete zabít odkudkoli pomocí kill PID

Pokud ztratíte přehled o svém PID, můžete použít pstree -pa $USER nebo pgrep -fl '.*PROCESS.*', které vám pomohou najít

2
errant.info

Co pro mě funguje docela dobře, je:

while sleep 1; do COMMAND; done

Funguje to proto, že spánek 1 se chvíli drží a pokud se dostane ctrl + c, vrátí se s nulu a smyčka se ukončí.

1
Iwan Aucamp

Použijte trap -

exit_()
{
    exit
}

while true
do
    echo 'running..'
    trap exit_ int
done
0
markroxor