Ukončení nekonečné smyčky

Mám příkaz, který chci nechat znovu spustit automaticky při každém ukončení, takže jsem spustil něco takového:

while [ 1 ]; do COMMAND; done; 

ale pokud nemůžu zastavit smyčku pomocí Ctrl-c , protože to jen zabije COMMAND a ne celá smyčka.

Jak bych dosáhl něčeho podobného, ale čeho mohu zastavit, aniž bych musel zavírat terminál?

Komentáře

  • Pokud jsem ‚ m v bash, stačí použít Ctrl-Z k zastavení úlohy a poté “ zabít% 1 “ zabít to.
  • Jen počkejte … Linus byl citován slovy: „Všichni víme, že Linux je skvělý … dělá nekonečné smyčky za 5 sekund. “ – takže opravdu … počkejte ještě několik sekund, mělo by to být hotové.
  • @PaulCager pracoval také pro mě! Proč to funguje tam, kde Ctrl-C ne?
  • @cirosantilli zabije vnější úlohu (bash “ wrapper „). V některých situacích například nebude ‚ okamžitě zabít “ COMMAND “ , pokud jej na pozadí, může se proklouznout kolem živého, i když je ‚ rodič mrtvý. Ale smyčka je mrtvá a to je ‚ důležitou součástí.

Odpověď

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

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

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

Stav ukončení 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 pomocí control-C, výstupní kód bude 130, protože SIGINT je signál 2 v systémech Unix. Takže:

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

Komentáře

  • Je třeba zmínit, že to ve skutečnosti není zaručeno, mnoho aplikací to neudělá.
  • @ Kyle Jones: můžete odkazovat na dokumenty POSIX / GNU, které to zmiňují?
  • @cirosantilli Hotovo.
  • @ KyleJones díky! Stále v praxi nefunguje pro COMMAND = paplay alert.ogg, možná proto, že paplay zpracovává signál?
  • @cirosantilli Ano, to je ‚ důvod. Pokud proces zpracovává signál a končí, je to ‚ odlišné od procesu ukončeného neošetřeným signálem.

Odpověď

Svou úlohu můžete zastavit a dát ji na pozadí, když běží, pomocí ctrl + z . Poté může vaši práci zabít pomocí:

$ kill %1 

Kde [1] je číslo vaší úlohy.

Komentáře

  • Viz také tuto odpověď , kde najdete vysvětlení a další.
  • Tato relativně nedávná odpověď jednoduše funguje. upvoted. +1
  • Hodně jste mi pomohli. To je to, co jsem hledal v této otázce 🙂

Odpovědět

Řekl bych, že by mohlo být nejlepší vložit nekonečnou smyčku do skriptu a zpracovávat tam signály. Zde je základní výchozí bod . Jsem si jistý, že to budete chtít upravit tak, aby vyhovovalo. Skript používá trap k zachycení ctrl c (nebo SIGTERM), zruší příkaz (zde jsem použil sleep jako test) a ukončí se.

cleanup () { kill -s SIGTERM $! exit 0 } trap cleanup SIGINT SIGTERM while [ 1 ] do sleep 60 & wait $! done 

Komentáře

  • Pěkné. Zde ‚ jsem použil tento tip k vytvoření obálky automatického spuštění netcat: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • pokud přidáte tento trap přístup ke stejnému (bash) skriptu s nekonečnou smyčkou, která má být zabita, použijte $$ místo $! (viz zde )

Odpověď

Obvykle podržím Ctrl-C . Dříve nebo později se „zaregistruji mezi COMMAND“ s a tím ukončit smyčku while. Možná existuje lepší způsob.

Komentáře

  • Nevím proč, ale u některých PŘÍKAZŮ jako paplay u souboru 1 s selže .
  • Fungovalo to na mě
  • to je ‚ hrubá síla všech řešení zde. : /

Odpověď

Pokud spustíte bash s -e ukončí se za jakýchkoli chybových podmínek:

#!/bin/bash -e false # returns 1 echo This won"t be printed 

Komentáře

  • První řádek je zdaleka nejjednodušší řešení pro triviální skript, kterému ‚ nechcete věnovat příliš mnoho času!

Odpovědět

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; 

Komentáře

  • Velmi elegantní řešení. Ale ‚ to nebude fungovat, pouze pokud příkaz COMMAND vždy vrátí stav úspěšného ukončení?
  • Ano @howardh, že ‚ s správné.

Odpověď

  1. Proces můžete vždy zabít pomocí jeho PID, tam “ není třeba zavírat terminál
  2. Pokud chcete spustit něco v nekonečné smyčce jako démon, měli byste to dát na 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 výzvu opustíte pomocí ctrl+d, úloha na pozadí nebude ukončena a můžete ji kdykoli zabít odkudkoli pomocí kill PID

Pokud ztratíte přehled o svém PID, můžete jej najít pomocí pstree -pa $USER nebo pgrep -fl ".*PROCESS.*"

Odpověď

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

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

V pořadí k zabíjení smyčky stačí:

rm .runcmd && kill `pidof COMMAND` 

Odpovědět

Co funguje rozumně pro mě je:

 while sleep 1; do COMMAND; done  

Funguje to, protože spánek 1 se drží za while a if it gets ctrl + c it return with non zero and the loop will terminate.

Komentáře

  • +1, doba spánku může být také sníženo na 0.5 nebo 0.1: while sleep 0.1; do COMMAND; done

Odpověď

Použijte trap

 exit_() { exit } while true do echo "running.." trap exit_ int done  

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *