You are not logged in.

#1 2010-05-20 03:10:52

demian
Member
From: Frankfurt, Germany
Registered: 2009-05-06
Posts: 709

bash: need a clever condition

Hi guys,

I'm having trouble with a condition in bash and I'd really appreciate some suggestions.

The relevant part of my script:

HDMI2=$(xrandr | grep HDMI2)
case "$HDMI2" in
    "HDMI2 connected ("*)   xrandr --output LVDS1 --off --output HDMI2 --auto 
                            sh $USERHOME/.wallpaper &;;
    "HDMI2 disconnected"*)  (sleep 2 && xrandr --output LVDS1 --off --output HDMI2 --auto
                            sleep 3 && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper
                            sleep 7 && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper)&;;
    *);;
esac

This is part of a script that gets called whenever my laptop is plugged into the docking station. It changes the output screen from the laptops display to my bigger external monitor.

Now, the external monitor isn't always recognized immediately. Sometimes there's a delay of 3 - 12 seconds so that HDMI2 reads as "HDMI2 disconnected" during that time.
As a workaround I've added the "HDMI2 disconnected"-part and made it try changing the screen again 2, 5 and 12 seconds after the initial try.

It works but it's not pretty and it makes my screen flash three times.
To stop the chain of xrandr when the command succeeds in changing the output I tried to introduce conditions like the following:

EXTOFF=$(xrandr | grep 'HDMI2 disconnected' | wc -l)
[...](sleep 2 && xrandr --...
sleep 3 && [ $EXTOFF = 1 ] && xrandr...
sleep 7 && [ $EXTOFF = 1 ] && xrandr...)&

I've tried many variations, with or without ampersand, with case and if statements but the xrandr command always gets executed three times.

Long story short the screen still flashes and i can't figure out a better solution. I'm hoping you have some ideas.

Regards,
demian

P.S.:
Here's the whole script: http://pastebin.com/Rbh7gR3A

Last edited by demian (2010-05-20 03:12:34)


no place like /home
github

Offline

#2 2010-05-20 03:53:24

kazuo
Member
From: São Paulo/Brazil
Registered: 2008-03-18
Posts: 413
Website

Re: bash: need a clever condition

I think that your condition is wrong. But this can be a bashism... What about this

while [[ $(xrandr|grep -c "HDMI2 disconnected") != 0 ]]; do xrandr; sleep 2 ;done

Last edited by kazuo (2010-05-20 03:57:46)

Offline

#3 2010-05-20 04:32:16

catweazle
Member
From: Germany
Registered: 2006-12-14
Posts: 24

Re: bash: need a clever condition

Hi demian,

in the first line of your second code snippet you evaluate the result of the xrandr call and store it in the variable EXTOFF. In your subsequent lines you just re-check that value, but I believe what you intended is to get the xrandr result re-evaluated at that time.

Try this:

In your first line:  EXTOFF="xrandr | grep 'HDMI2 disconnected' | wc -l"

In the following lines use eval $EXTOFF  instead of just $EXTOFF

Hope this helps.

Offline

#4 2010-05-20 12:39:36

demian
Member
From: Frankfurt, Germany
Registered: 2009-05-06
Posts: 709

Re: bash: need a clever condition

You're both right, thank you for your suggestions.
My condition was ill-thought-out and i needed to reevaluate it every time.
If the display stays disconnected i don't want an infinite while do loop in the background so now I'm using the following:

EXTON="xrandr | grep -c 'HDMI2 connected ('"
EXTOFF="xrandr | grep -c 'HDMI2 disconnected'"
(sleep 1 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 1st try" && echo >> $LOG
sleep 1 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 2nd try" && echo >> $LOG
sleep 3 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 3rd try" && echo >> $LOG
sleep 3 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 4th try" && echo >> $LOG
sleep 4 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 5th try" && echo >> $LOG
sleep 12 && [ $(eval $EXTON) = 1 ] && xrandr --output LVDS1 --off --output HDMI2 --auto && sh $USERHOME/.wallpaper && $verbose && logger "HDMI2: succeeded at 6th try" && echo >> $LOG
sleep 1 && [ $(eval $EXTOFF) = 1] && logger "HDMI2: failed to activate" && echo >> $LOG) &;;

I can't say it's pretty but it does exactly what i want it to so thanks again.

Regards,
demian


no place like /home
github

Offline

#5 2010-05-21 00:31:23

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: bash: need a clever condition

Something like this might be a bit cleaner (note: untested, but I think it'll work) - not entirely sure what $verbose is so I took a guess tongue

EXTON="xrandr | grep -c 'HDMI2 connected ('"
EXTOFF="xrandr | grep -c 'HDMI2 disconnected'"
for $((i=0; i<10; i++)); do
    sleep 1
    if [ $(eval $EXTON) = 1 ]; then
        xrandr --output LVDS1 --off --output HDMI2 --auto
        sh $USERHOME/.wallpaper
        if [ -n "$verbose" ]; then
            logger "HDMI2: succeeded at try number $i"
            echo >> $LOG
        fi
        break
    fi
done

if [ $(eval $EXTOFF) = 1 -a -n "$verbose"]; then
    logger "HDMI2: failed to activate"
    echo >> $LOG
fi

Offline

#6 2010-05-21 17:23:04

demian
Member
From: Frankfurt, Germany
Registered: 2009-05-06
Posts: 709

Re: bash: need a clever condition

 line 39: `$((i=0; i<10; i++))': not a valid identifier

I'm looking into three-expression loops now but i wouldn't mind if anyone could tip me to the solution wink.

duh, i just had to remove the $ in front of the ((.
Code now looks like this:

$verbose && logger "switching monitor"
case "$HDMI2" in
    "HDMI2 connected ("*)   $verbose && logger "-> switching to HDMI2"
                xrandr --output LVDS1 --off --output HDMI2 --auto 
                sh $USERHOME/.wallpaper &;;
    "HDMI2 disconnected"*)  $verbose && logger "-> HDMI2 not connected"
                $verbose && logger "-> retrying every second for the next 20 seconds"
                (for ((i=0; i<=20; i++));do
                sleep 1
                if [ $(eval $EXTON) = 1 ]; then
                    xrandr --output LVDS1 --off --output HDMI2 --auto
                    $verbose && logger "HDMI2: succeeded at try number $i"
                    echo >> $LOG
                    break
                fi
                done
                if [ $(eval $EXTOFF) = 0 ]; then
                    sh $USERHOME/.wallpaper
                $verbose && logger "restarting conky"
                su -c "killall conky" $USER
                LANG=en_US.UTF-8 su -c "conky -q -c $USERHOME/.conkydock &" $USER &
                else
                logger "HDMI2: failed to activate"
                echo >> $LOG            
                fi) &;;
    "HDMI2 connected 1"*)   $verbose && logger "-> HDMI2 already active";;
    *)                $verbose && logger "-> undefined display state";;
esac

Thank you very much.

P.S.:
[[ "$1" = '-v' ]] && verbose=true || verbose=false

Last edited by demian (2010-05-21 17:35:32)


no place like /home
github

Offline

#7 2010-05-21 17:30:06

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,799
Website

Re: bash: need a clever condition

remove the dollar sign

for ((i=0; i<10; i++)); do

is proper bash syntax as far as i can tell.  just a typo on cerebral's part methinks.

/edit:

no offense to cerebral, but i prefer function calls to the eval syntax.  i think it makes more sense and reads intuitively.

# these will return 0 or 1 for success/failure of the grep
ext_on()  { xrandr | grep -Fq 'HDMI2 connected'; }
ext_off() { xrandr | grep -Fq 'HDMI2 disconnected'; }

do_on_work() {
  # put here all things you want run when connected
}

do_off_work() {
  # put here all things you want run when not connected
}

for ((i=0; i<20; i++)); do
  if ext_on; then
    do_on_work
    break;
  fi
done

ext_off && do_off_work

just another way to skin the cat smile. (also, untested).

Last edited by brisbin33 (2010-05-21 18:09:26)

Offline

#8 2010-05-21 17:36:29

demian
Member
From: Frankfurt, Germany
Registered: 2009-05-06
Posts: 709

Re: bash: need a clever condition

yeah, thanks, i figured it out, too. wasn't that hard, after all roll

btw, i recently stumbled over your scripts and found them to be a nice source to improve my bash a little. i'm using some of them too, like updatehosts or goodsong. Just wanted to say thanks for sharing them.

Regards,
demian

P.S.: I totally forgot to mention that i'm using wifi-pipe, your openbox pipe menu for wireless connection via netcfg. It's awesome!

Last edited by demian (2010-05-21 17:46:52)


no place like /home
github

Offline

#9 2010-05-21 17:39:38

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,799
Website

Re: bash: need a clever condition

demian wrote:

btw, i recently stumbled over your scripts and found them to be a nice source to improve my bash a little. i'm using some of them too, like updatehosts or goodsong. Just wanted to say thanks for sharing them.

thank you!

Offline

#10 2010-05-22 13:08:21

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: bash: need a clever condition

brisbin33 wrote:

remove the dollar sign.  just a typo on cerebral's part methinks.

Damn, yeah.  I missed that. tongue  S'what I get for not running it through bash once or twice to weed out the obvious bugs

brisbin33 wrote:

no offense to cerebral, but i prefer function calls to the eval syntax.  i think it makes more sense and reads intuitively.

Agreed - the eval syntax wasn't my idea in the first place, I just didn't bother cleaning it up.

Offline

Board footer

Powered by FluxBB