0

I need to perform an arithmetic operation inside a bash loop as explained below

CYCLE?=3
COUNT=1

download_when_ready: ## Will try the download operations many times till it succeeds or it reaches 10 tries
    while ! composer update $(bundle) 2> /dev/null && [[ $(COUNT) -lt 10 ]]; \
    do \
        COUNT=$$(( $(COUNT)+1 )); \
        SLEEP=$$(( ($(COUNT) / $(CYCLE)) + ($(COUNT) % $(CYCLE)) )); \
        echo "count $(COUNT)"; \
        echo "cycle $(CYCLE)"; \
        echo "sleep $(SLEEP)"; \
        sleep $(SLEEP); \
    done

This never stops and gives the following:

count 0
cycle 4
sleep 0

count 0
cycle 4
sleep 0

....

count 0
cycle 4
sleep 0

As you can see, variables have the initial values and never change !

UPDATE

PRETTY_NAME="SUSE Linux Enterprise Server 11 SP4"

However the following code keeps the value of $$c empty, before the while loop and inside it.

CYCLE?=3
COUNT=1

download_when_ready: ## Will try the download operations many times till it succeeds or it reaches 10 tries
    @c=$(COUNT);
    @echo $$c;
    while ! composer update $(bundle) 2> /dev/null && [[ $(COUNT) -lt 10 ]]; \
    do \
        echo "$$c"; \
    done
3

UPDATE

Thanks to @Kusalananda comment, I figured it out.

I used variable as initial values for variables

CYCLE?=3
COUNT=1

download_when_ready: ## Will try the download operations many times till it succeeds or it reaches 10 tries
    while ! composer update $(bundle) 2> /dev/null && [ "$$c" -lt 10 ]; \
    do \
        c=$$(( $${c:-$(COUNT)}+1 )); \
        s=$$(( ($$c / $(CYCLE)) + ($$c % $(CYCLE)) )); \
        echo "count $$c"; \
        echo "cycle $(CYCLE)"; \
        echo "sleep $$s"; \
        sleep $$s; \
    done

And this does work!

count 1
cycle 4
sleep 1
count 2
cycle 4
sleep 2
count 3
cycle 4
sleep 3
count 4

Thanks to @Kusalananda & @Stéphane Chazelas

  • 1
    [[ $(COUNT) -lt 10 ]] will be expanded by make to [[ 1 -lt 10 ]] before calling sh. So that tell will always be true. Also note that [[...]] is not sh syntax. – Stéphane Chazelas Jan 26 '18 at 11:28
  • @StéphaneChazelas True! fixed now thanks! Yeah [[ ... ]] must be bash I assume, and that's fine for me... Thanks again! – smarber Jan 26 '18 at 11:35
  • 2
    [[...]] is ksh syntax, also supported by bash and zsh. It's not in sh. If you want to use that, you should set the SHELL make variable (which is independant from the SHELL environment variable) to a shell that supports that non-standard syntax. But note that not all systems have bash installed and those that do don't have it always in the same place (can be /usr/gnu/bin/bash, /usr/local/bin/ash, /opt/gnu/bin/bash... depending on the system). Just use [ "$$c" -lt 10 ] and you won't have to require bash/ksh/zsh – Stéphane Chazelas Jan 26 '18 at 11:59
  • 1
    @smarber, yep (see pubs.opengroup.org/onlinepubs/9699919799/utilities/… ). Though you could just begin the script with c=$(COUNT) and you wouldn't need the default value – ilkkachu Jan 26 '18 at 12:27
  • 2
    You need the backslash at the end of c=$(COUNT). Otherwise make runs two separate sh instances. That's why you have ; at the end of your line. That's because those lines end up joined together because of the backslash. – Stéphane Chazelas Jan 26 '18 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.