Как повторить цикл n раз в Bash

9

У меня ниже сценарий, как:

if [file exists]; then
   exit   
elif
   recheck if file exist (max 10 times)
   if found exit else recheck again as per counter  
fi 
Rocky86
источник
Это очень основная особенность в оболочках. Вы даже исследовали это?
Пешке
Да. Но не получил ожидаемый вывод из моего кода. Также хочу написать как можно более сокращенно
Rocky86
1
@Peschke, ну, им понадобятся как минимум три основные функции (циклы, условные выражения, тестирование файла, выход из цикла). По крайней мере, вопрос достаточно ясен. Хотя он может содержать набросок того, что пытался Рокки, но тогда кто-нибудь все равно перепишет его в ответах. ;)
ilkkachu

Ответы:

9

Есть много способов сделать этот цикл.

С ksh93синтаксисом (также поддерживается zshи bash):

for (( i=0; i<10; ++i)); do
    [ -e filename ] && break
    sleep 10
done

Для любой POSIX-подобной оболочки:

n=0
while [ "$n" -lt 10 ] && [ ! -e filename ]; do
    n=$(( n + 1 ))
    sleep 10
done

Оба цикла спят по 10 секунд в каждой итерации, прежде чем снова проверять наличие файла.

После завершения цикла вам придется в последний раз проверить наличие файла, чтобы выяснить, завершился ли цикл из-за 10-кратного выполнения или из-за появления файла.

Если вы хотите, и если у вас есть доступ к inotify-tools, вы можете заменить sleep 10звонок на

inotifywait -q -t 10 -e create ./ >/dev/null

Это приведет к ожиданию события создания файла в текущем каталоге, но истечет время ожидания через 10 секунд. Таким образом, ваш цикл завершится, как только появится указанное имя файла (если оно появилось).

Полный код с inotifywait(заменить на, sleep 10если вы этого не хотите) может выглядеть так

for (( i=0; i<10; ++i)); do
    [ -e filename ] && break
    inotifywait -q -t 10 -e create ./ >/dev/null
done

if [ -e filename ]; then
    echo 'file appeared!'
else
    echo 'file did not turn up in time'
fi
Кусалананда
источник
С помощью inotify вы можете почти заменить весь цикл. Просто проверьте, есть ли файл, и если нет, inotifywait в течение 100 секунд. Почти, так как файл может быть создан только между тестом и inotify, и вы будете спать в течение полных 100 секунд, прежде чем
истечет
1
@ilkkachu Да, это хорошая идея, но здесь я просто использую inotifywaitзамену sleep.
Кусалананда
8

Если число не является переменной, вы можете использовать расширение скобки:

for i in {1..10}   # you can also use {0..9}
do
  whatever
done

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

count=10
for i in $(seq $count)
do
  whatever
done
xenoid
источник
Я хочу зациклить, только если файл не найден (макс. 10 раз). Если найден, скажем, в третий раз, затем успешно
завершите работу
@ Rocky86: Это не противоречит решению, предложенному ксеноидом. Никто не заставляет вас считать до конца ....
user1934428
Мне нравится этот$(seq $count)
рабочий
0
n=0
until [ "$((n+=1))" -gt 10 ]
do    <exists? command exit
done
echo oh noes!

хотя test -e file && exitболее гибкий

mikeserv
источник
Почему знак вопроса? Обратите внимание, что поведение для глобусов в цели перенаправлений варьируется между оболочками.
Стефан Шазелас
2
Обратите внимание, что у него есть побочный эффект открытия файла, который, например, для fifos может быть довольно плохим (хуже с символической ссылкой на / dev / watchdog для Linux, например)
Стефан Шазелас
Даже в Bash, где этот файл будет выглядеть подобным exists1образом, он все равно печатает кучу ошибок, если / когда соответствующий файл не найден. (Также это ошибки, если есть несколько совпадений.) Любая другая оболочка, которую я тестировал, похоже, дает ошибки в любом случае ...
ilkkachu
@ikkachu - да. это было своего рода точка. если происходит ошибка, скрипт сообщает. если stderr должен быть подавлен, подавьте его done 2<>/dev/null. это bashделает сценарий? я думал, что это только в -iнеконструктивном контексте. тем не менее, exists?так же, как имя наполнителя, как file. но да, я ненавижу цитировать в перенаправлениях - если винты так много.
mikeserv
@ Стефан - нет причин, правда. но да, пятерки, нечитаемые ... вот почему я заметил test -e.
mikeserv