1

Why is this loop not breaking(ending due to if statement) or using the newly incremented value of $c variable? Tried c=expr $c + 1 with and without " double quote.

export c=1; ssh auser@someserver "until [[ 1 -eq 2 ]]; do echo \"Value of 'c' == $c\"; c=`expr $c + 1`; echo \"$c - Incremented value: `expr $c + 1`\"; if [[ $c -gt 5 ]]; then break; fi; sleep 2 ; done;"

or

$ export c=1; ssh root@$CHEF_SERVER \
> "until [[ 1 -eq 2 ]]; do \
>   echo \"Value of 'c' == $c\"; c=`expr $c + 1`; \
>   echo \"$c - Incremented value: `expr $c + 1`\"; \
>   if [[ $c -gt 5 ]]; then break; fi; \
>   sleep 2; \
>   echo; \
> done;"

Output is infinte: I had to ^c it.

Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Value of 'c' == 1
1 - Incremented value: 2
Killed by signal 2.
Inian
  • 80,270
  • 14
  • 142
  • 161
AKS
  • 16,482
  • 43
  • 166
  • 258
  • Can you split the code up onto multiple lines? It's really difficult to read. – Will Richardson Mar 06 '19 at 02:43
  • John, condition in `until` is intentional. I want that to run infinite. But I want the if statement to work and `break` the shenzi (issue I'm getting in Production :) ). – AKS Mar 06 '19 at 02:59
  • not a bash guru, but I'd assume that the `break` would only apply to the current `do` and the `until` would just run it again. – lecstor Mar 06 '19 at 03:00
  • 1
    @lecstor I see only one loop `until` here (either `for`, `while` or `until` etc loops use `do` and `done`) in BASH / Shell to start and end it's scope/boundary. – AKS Mar 06 '19 at 03:01

2 Answers2

2

You need to understand that shell variables needs to be properly escaped before using them in conditionals or assignments inside ssh under double quotes. Not doing so will let the variables expand even before the commands are executed over the remote machine. So in your case, no matter if you increment c or not the variable is expanded and condition remains always as below in the remote machine.

if [[ 1 -gt 5 ]]; then
    break
fi

Also expr is pretty much outdated, use a traditional C style loop increment using ((..)) as and escape all the invocations of variable inside to defer the variable expansion

ssh root@$CHEF_SERVER "
until [[ 1 -eq 2 ]]; do
    ((c = c+1))
    echo "Incremented value: \$c"
    if [[ \$c -gt 5 ]]; then
        break
    fi
    sleep 2
done"
Inian
  • 80,270
  • 14
  • 142
  • 161
  • My bad, yes, it worked, was missing `;` after `((c = c+1));` – AKS Mar 06 '19 at 03:21
  • My understanding was, we only need to escape a variable like you did, only if it was defined new/fresh within the SSH session. Seems like, that's not true. It's funny that within `(( ))`, we didn't have to escape it. – AKS Mar 06 '19 at 03:22
  • 1
    @ArunSangal Whether a variable reference gets resolved locally or remotely depends only on syntax, not on where/how it's defined. If it's in double-quotes and it starts with an unescaped `$`, it will be expanded by the local shell before being sent over `ssh`. The references in `(( ))` aren't resolved locally because they don't start with `$`. Note that variables are *not* shared across the connection; any value assigned to a variable on the local computer (e.g. with `export c=1`) has nothing to do with any variable on the remote system, and vice versa. – Gordon Davisson Mar 06 '19 at 05:07
0

Variables are expanded inside double-quoted strings. So are backticks.

You declare a variable c and assign it the value 1.

You then call ssh and pass it a double-quoted string.

The shell invoked by ssh sees:

until [[ 1 -eq 2 ]]; do 
   echo "Value of 'c' == 1"; c=2; 
   echo "1 - Incremented value: 2"; 
   if [[ 1 -gt 5 ]]; then break; fi; 
   sleep 2; 
   echo; 
done;
jhnc
  • 11,310
  • 1
  • 9
  • 26