Sintaxe para um Bash de linha única infinito enquanto loop

635

Estou tendo problemas para encontrar a combinação certa de ponto e vírgula e / ou chaves. Eu gostaria de fazer isso, mas como uma linha da linha de comando:

while [ 1 ]
do
    foo
    sleep 2
done
Brian Deacon
fonte
4
substitua novas linhas por ponto e vírgula. O mesmo funciona para loops.
Tom
23
@ Tom: isso nem sempre funciona. depois de o fazer, tem de ter o primeiro comando, não um ponto e vírgula
Stefano Borini

Respostas:

1232
while true; do foo; sleep 2; done

A propósito, se você digitar como uma multilinha (como está sendo exibida) no prompt de comando e chamar o histórico com a seta para cima, você o encontrará em uma única linha, corretamente pontuada.

$ while true
> do
>    echo "hello"
>    sleep 2
> done
hello
hello
hello
^C
$ <arrow up> while true; do    echo "hello";    sleep 2; done
Stefano Borini
fonte
2
"se você digitar como uma multilinha (como está sendo exibida) no prompt de comando e chamar o histórico com a seta para cima, você o obterá em uma única linha, pontuada corretamente." não era verdade para mim.
Vincent Scheib
@VincentScheib, marque a cmdhistopção se você estiver usando o bash?
Alok Singhal
Excelente! Funciona perfeitamente no Mavericks (Mac OS-X 10.9) e me permite manter uma VPN em execução. O Openconnect se desconecta após algumas horas com um erro de cookie incorreto. Então eu coloquei o comando openconnect em um shell script, o sudo su para se tornar root, e usar esta linha cmd: while true; do sh /Users/myuser/bin/vpn ; done
Blisterpeanuts
170

Também é possível usar o comando sleep na condição while. Fazendo uma linha parecer mais limpa.

while sleep 2; do echo thinking; done
Anssi
fonte
16
Bem, isso faz mais do que apenas alterar a sintaxe - ele executará o comando após o sono. Na resposta anterior, o comando é executado imediatamente. Apenas algo a ser observado.
DanGordon
@DanGordon while echo thinking ; do sleep 2 ; done Claro, se o [enquanto] comando falhar, o loop termina, então você teria que while echo thinking || true ; do sleep 2 ; donemas então você está de volta parawhile true ; ...
Brian Carcich
69

O cólon é sempre "verdadeiro":

while :; do foo; sleep 2; done
ajaaskel
fonte
15
por que o cólon é sempre verdadeiro?
Jürgen Paul
8
@ Abacaxi no fundo do mar: Na página do manual do bash: (na seção COMANDO DE CONSTRUÇÃO DE CASCOS) : [arguments] Sem efeito; o comando não faz nada além de expandir argumentos e executar redirecionamentos especificados. Um código de saída zero é retornado.
Adrian W
2
esta sintaxe é recomendada como: faz parte do próprio shell, ou seja: é um comando interno do shell.
avner
@analytik então você está dizendo que é um mais ou um menos? ;-)
Brian Carcich 14/11/19
33

Você pode usar ponto e vírgula para separar instruções:

$ while [ 1 ]; do foo; sleep 2; done
mipadi
fonte
3
Eu gosto desta resposta porque explica quando e por que; (ponto e vírgula) é necessário.
Sr. AndreasGeo
29

Você também pode fazer uso do untilcomando:

until ((0)); do foo; sleep 2; done

Observe que, ao contrário de while, untilexecutaria os comandos dentro do loop, desde que a condição de teste tenha um status de saída que não seja zero.


Usando um whileloop:

while read i; do foo; sleep 2; done < /dev/urandom

Usando um forloop:

for ((;;)); do foo; sleep 2; done

Outra maneira de usar until:

until [ ]; do foo; sleep 2; done
devnull
fonte
O until ((0)); do foo; sleep 2; doneparece não funcionar. É infinito contínuo.
030
11

Um loop infinito muito simples .. :)

while true ; do continue ; done

Na sua pergunta, seria:

while true; do foo ; sleep 2 ; done
Mack
fonte
8

Gosto de usar o ponto-e-vírgula apenas para a instrução WHILE e o operador && para fazer o loop fazer mais de uma coisa ...

Então eu sempre faço assim

while true ; do echo Launching Spaceship into orbit && sleep 5s && /usr/bin/launch-mechanism && echo Launching in T-5 && sleep 1s && echo T-4 && sleep 1s && echo T-3 && sleep 1s && echo T-2 && sleep 1s && echo T-1 && sleep 1s && echo liftoff ; done
Thomas
fonte
1
Bem, o uso de &&no loop é o mesmo de qualquer outro momento, não é mesmo. Você precisa que a segunda coisa aconteça apenas se a primeira acontecer, e use &&outra coisa ;é suficiente. Realmente, você deseja manter o conteúdo desse loop curto e simples, idealmente apenas um comando, para uma função ou um script.
Thecoshman 07/07/2015
7

Para uso simples processo de observação watch, em vez

Christian Schwarz
fonte
6

Usando while:

while true; do echo 'while'; sleep 2s; done

Usando forLoop:

for ((;;)); do echo 'forloop'; sleep 2; done

Usando Recursion(um pouco diferente do anterior, a interrupção do teclado não o interrompe)

list(){ echo 'recursion'; sleep 2; list; } && list;
Muhammad Soliman
fonte
5

Se você deseja que o loop while pare após alguma condição e seu foocomando retorne diferente de zero quando essa condição for atendida, você poderá fazer com que o loop quebre assim:

while foo; do echo 'sleeping...'; sleep 5; done;

Por exemplo, se o foocomando estiver excluindo itens em lotes e retornará 1 quando não houver mais nada a ser excluído.

Isso funciona bem se você tiver um script personalizado que precise executar um comando várias vezes até alguma condição. Você escreve o script para sair 1quando a condição for atendida e sair 0quando deve ser executado novamente.

Por exemplo, digamos que você tenha um script python batch_update.pyque atualize 100 linhas em um banco de dados e retorne 0se houver mais a atualizar e 1se não houver mais. O comando a seguir permitirá que você atualize as linhas 100 por vez, com suspensão por 5 segundos entre as atualizações:

while batch_update.py; do echo 'sleeping...'; sleep 5; done;
Yep_It's_Me
fonte
e como você sairia?
AK_ 17/01/19
Você faz o foocomando sair com código 1quando deseja que o loop while seja interrompido. Atualizei minha resposta com um exemplo.
Yep_It's_Me
2

Se eu posso dar dois exemplos práticos (com um pouco de "emoção").

Isso grava o nome de todos os arquivos terminados com ".jpg" na pasta "img":

for f in *; do if [ "${f#*.}" == 'jpg' ]; then echo $f; fi; done

Isso os exclui:

for f in *; do if [ "${f#*.}" == 'jpg' ]; then rm -r $f; fi; done

Apenas tentando contribuir.

Roger
fonte
1
@JKnight - para esses exemplos, você não faria ls -1 *.jpgerm *.jpg
Kevin Fegan
2
Ambos não são loops infinitos e não são loops.
Marian
2

Você pode tentar isso também AVISO: isso você não deve fazer, mas como a pergunta está pedindo um loop infinito sem fim ... é assim que você poderia fazê-lo.

while [[ 0 -ne 1 ]]; do echo "it's looping";   sleep 2; done
grepit
fonte
Por que você faria isso?
Gnourf_gniourf
2
porque Brian Deacon, que postou a pergunta, queria um loop infinito. É mais do que uma maneira de esfolar um gato que é tudo
grepit