Синтаксис для однострочного бесконечного цикла Bash

636

У меня возникают проблемы с правильным сочетанием точек с запятой и / или фигурных скобок. Я хотел бы сделать это, но в качестве одной строки из командной строки:

while [ 1 ]
do
    foo
    sleep 2
done
Брайан Дикон
источник
4
заменить символы новой строки на точки с запятой. То же самое работает для петель.
Том
23
@Tom: это не всегда работает. после этого у вас должна быть первая команда, а не точка с запятой
Стефано Борини

Ответы:

1233
while true; do foo; sleep 2; done

Кстати, если вы наберете его как многострочное (как вы показываете) в командной строке, а затем вызовете историю со стрелкой вверх, вы получите ее в одной строке, правильно пунктуированной.

$ while true
> do
>    echo "hello"
>    sleep 2
> done
hello
hello
hello
^C
$ <arrow up> while true; do    echo "hello";    sleep 2; done
Стефано Борини
источник
2
«если вы наберете его как многострочное (как вы показываете) в командной строке, а затем вызовете историю со стрелкой вверх, вы получите ее в одной строке, правильно пунктуированной». не было правдой для меня.
Винсент Шейб
@ VincentScheib, отметьте cmdhistопцию, если вы используете bash?
Alok Singhal
Отлично! Отлично работает на Mavericks (Mac OS-X 10.9) и позволяет мне поддерживать работу VPN. Openconnect отключается через несколько часов с ошибкой cookie. Поэтому я поместил команду openconnect в скрипт оболочки, sudo su, чтобы стать пользователем root, и использую эту строку cmd: while true; do sh /Users/myuser/bin/vpn ; done
Blisterpeanuts
170

Также возможно использовать команду сна в состоянии while. Делать однострочник более чистым imho.

while sleep 2; do echo thinking; done
Анси
источник
16
Что ж, это больше, чем просто изменение синтаксиса - он выполнит команду после сна. В предыдущем ответе команда выполняется сразу. Просто кое-что отметить.
ДанГордон
@DanGordon while echo thinking ; do sleep 2 ; done Конечно, если команда [while] терпит неудачу, цикл завершается, так что вам придется это сделать, while echo thinking || true ; do sleep 2 ; doneно тогда вы вернетесь кwhile true ; ...
Brian Carcich
69

Двоеточие всегда "верно"

while :; do foo; sleep 2; done
ajaaskel
источник
15
почему двоеточие всегда верно?
Юрген Павел
8
@Pineapple Under the Sea: со страницы руководства bash: (в разделе КОМАНДЫ, ПОСТРОЕННЫЕ SHELL) : [arguments] Нет эффекта; команда не делает ничего, кроме расширения аргументов и выполнения любых указанных перенаправлений. Возвращается нулевой код выхода.
Адриан W
2
этот синтаксис рекомендуется так: является частью самой оболочки, т.е. является встроенной командой оболочки.
Авнер
@analytik так ты говоришь, что это плюс или минус? ;-)
Брайан Карчич
33

Вы можете использовать точки с запятой для разделения операторов:

$ while [ 1 ]; do foo; sleep 2; done
mipadi
источник
3
Мне нравится этот ответ, потому что он объясняет, когда и почему; (точка с запятой) требуется.
Mr. AndreasGeo
29

Вы также можете использовать untilкоманду:

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

Обратите внимание, что, в отличие от while, untilбудет выполнять команды внутри цикла, пока условие теста имеет статус выхода, который не равен нулю.


Используя whileцикл:

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

Используя forцикл:

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

Еще один способ использования until:

until [ ]; do foo; sleep 2; done
devnull
источник
until ((0)); do foo; sleep 2; doneНе похоже на работу. Это непрерывное бесконечное.
030
11

Очень простой бесконечный цикл .. :)

while true ; do continue ; done

На ваш вопрос это будет так:

while true; do foo ; sleep 2 ; done
Mack
источник
8

Мне нравится использовать точки с запятой только для оператора WHILE, а оператор &&, чтобы цикл делал больше, чем одно ...

Поэтому я всегда так делаю

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
Томас
источник
1
Ну, использование &&в цикле такое же, как и в любое другое время, не так ли. Нужно ли, чтобы второе происходило только в том случае, если первое происходит, тогда достаточно использовать &&другое ;. Действительно, вы хотите, чтобы содержимое этого цикла было коротким и простым, в идеале всего одна команда, то есть функция или скрипт.
Thecoshman
7

Для простого наблюдения за процессом используйте watchвместо

Кристиан Шварц
источник
6

Использование while:

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

Используя forLoop:

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

Использование Recursion, (немного отличное от описанного выше, прерывание клавиатуры не остановит его)

list(){ echo 'recursion'; sleep 2; list; } && list;
Мухаммед Солиман
источник
5

Если вы хотите, чтобы цикл while останавливался после некоторого условия, и ваша fooкоманда возвращает ненулевое значение при выполнении этого условия, вы можете заставить цикл прерываться следующим образом:

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

Например, если fooкоманда удаляет вещи в пакетном режиме и возвращает 1, когда нечего удалять.

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

Например, допустим, у вас есть скрипт Python, batch_update.pyкоторый обновляет 100 строк в базе данных и возвращает, 0если есть что-то еще для обновления и 1если их больше нет. Следующая команда позволит вам обновлять строки 100 за один раз с перерывами на 5 секунд между обновлениями:

while batch_update.py; do echo 'sleeping...'; sleep 5; done;
Yep_It's_Me
источник
и как бы вы вышли?
AK_
Вы делаете fooкоманду выхода с кодом, 1когда хотите, чтобы цикл while прервался. Я обновил свой ответ с примером.
Yep_It's_Me
2

Если я могу привести два практических примера (с небольшим количеством «эмоций»).

Это записывает имя всех файлов, оканчивающихся на «.jpg» в папке «img»:

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

Это удаляет их:

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

Просто пытаюсь внести свой вклад.

Роджер
источник
1
@JKnight - для этих примеров вы бы просто не сделали ls -1 *.jpgиrm *.jpg
Кевин Феган
2
Оба не являются бесконечными циклами и не циклами while.
Marian
2

Вы можете попробовать это тоже ВНИМАНИЕ: этого делать не следует, но поскольку вопрос заключается в бесконечном цикле без конца ... это то, как вы можете это сделать.

while [[ 0 -ne 1 ]]; do echo "it's looping";   sleep 2; done
grepit
источник
Зачем тебе это делать?
gniourf_gniourf
2
потому что Брайан Дикон, который разместил вопрос, хотел как бесконечный цикл. Это больше, чем один способ снять шкуру с кота, вот и все
grepit