"while" loop is not reading reading a variable's contents

I have setup a little script to illustrate my problem.

I have set up a while loop that I would like to keep looping as long as $output is equal to No screen session found

#!/bin/bash

echo Stopping server...

output=$(screen -S tls -X eval 'stuff "stop15"')

while [ "$output" = "No screen session found." ]
do 
        echo "$output"
        sleep 1
done

echo Server stopped!

When I run this script, it halts instantly:

Stopping server...
Server stopped!

Well ok, so I guess $output did not equal No screen session found..

However if I switch out the while loop for an until loop like so:

until [ "$output" = "No screen session found." ]

I should expect that my loop will now start looping as $output is not equal to the string as we just saw. And while the loop does keep looping, the echo $output command I added reveals that the loop should in fact terminate!

Stopping server...
No screen session found.
No screen session found.
No screen session found.
No screen session found.

As $output is equal to No screen session found.!

What is going on? Why does the while and until loop just ignore the contents of $output?

Asked By: Kuba0040

||

If you run your script with -x to enable tracing, like

bash -x myscript.sh

You will see:

+ echo Stopping server...
Stopping server...
++ screen -S tls -X eval 'stuff "stop15"'
' output='No screen session found.
' = 'No screen session found.' ']'
+ echo Server 'stopped!'
Server stopped!

As you can see, @muru was correct in their comment: there is a carriage return at the end of $output, so the string is failing to match.

Since you’re using Bash, a simple solution is to use a wildcard in your match expression:

#!/bin/bash

echo Stopping server...

output=$(screen -S tls -X eval 'stuff "stop15"')

while [[ "$output" = "No screen session found."* ]]
do 
        echo "$output"
        sleep 1
done

echo Server stopped!

Running this produces:

Stopping server...
No screen session found.
No screen session found.
.
.
.

As @DonHolgo points out, at this point you have an infinite loop, so you’ll need to fix that as well.


A better solution might be to look at the exit code from screen rather than trying to match the output. You can write something like this:

#!/bin/bash

echo Stopping server...

while ! screen -S tls -X eval 'stuff "date15"'; do
  sleep 1
done

echo Server stopped!

If I start this when screen is not running and then start a session in another terminal, I see:

Stopping server...
No screen session found.
No screen session found.
Server stopped!
Answered By: larsks
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.