user5356132 user5356132 - 15 days ago 5
Bash Question

Condition evaluating unexpectedly

i am trying to write a simple bash script for a custom screensaver, i want simple to go the screen black if in idle, and go back to normal if not.

#!/bin/bash
#sets display gamma very low, for screensaver purposes


idle=false
idle_after=3000 #in milliseconds

while true; do

#if system is idle
if [[ idle_now=$(xprintidle) -gt "$idle_after" && "$idle"=false ]] ;then

echo "1"

`xrandr --output HDMI-0 --brightness 0.01`
idle=true

fi

if [[ idle_now=$(xprintidle) -lt "$idle_after" && "$idle"=true ]] ; then
echo "2"
`xrandr --output HDMI-0 --brightness 1` #set screen back to normal
exit
fi


done


i really don't know why the second if query gets executed first.
i thought the idle variable is initialized "false" at startup
can someone explain this to me ? and if someone has improvements to give on my approach i 'would very appreciate that , thanks

Answer

Your test expressions are wrong.

The reason for 2nd if was executed first is that there are no spaces between operands and operators inside test ([[ and ]]).

For better understanding, let's see a possible variable substitution in the first loop assuming that xprintidle returns 10:

[[ idle_now=$(xprintidle) -lt "$idle_after" && "$idle"=true ]]
# becomes
[[ idle_now=10 -lt 3000 && false=true ]]

Now you wanted compare 10 against 3000, but now you're comparing the string "idle_now=10" against 3000. As any string is converted to zero if the characters are not digits, its like you did:

[[ 0 -lt 3000 && false=true ]]
# that becomes
[[ <true> && false=true ]]

Now, the second operand is also one string "false=true" (not a comparison), and any string converted to boolean is false when it's empty. That's not your case, the string has 10 characters, so it's evaluated to true.

[[ <true> && <true> ]]
# that becomes
<true>

Note: I used <true> and <false> just to clarify, they really are internal representation of boolean values.

Fixing it

I imagine idle_now was meant to be a variable that it's never used, so we'll ignore it.

So the if expressions should be:

[[ "$(xprintidle)" -gt "$idle_after" && "$idle" = false ]]
# and
[[ "$(xprintidle)" -lt "$idle_after" && "$idle" = true ]]