You are not logged in.

#1 2015-09-23 00:06:24

felixculpa
Member
From: Alberta, Canada
Registered: 2012-06-12
Posts: 252

[SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

Hi all. First off I guess I should give the context and then what I want to do...

I am using BSPWM and Lemonbar with a bash script piping info to it. I am wondering if it is possible to change the color on a  dynamic value depending on its current range. For example I'm using this to grab the audio volume:

# VOLUME
# ======
volInfo() {
  volStatus=$(amixer get Master | tail -n 1 | cut -d '[' -f 3 | sed 's/]//g')
  volLevel=$(amixer get Master | awk '/Front Left:/ {print $5}' | tr -dc "0-9" | sed 's/%//g' )

  if [ "$volStatus" == "on" ]
    then
    printf %s "%{Fgreen}$volLevel%{F-}"
  else
    # If it is muted, make the font red
    printf %s "%{Fred}$volLevel%{F-}"
  fi
}

So it is obvious you can change the color depending on a binary/boolean type status (on or off), but what if I wanted to have different colors depending on a range, in this case of my battery status?

Current battery info getting echoed to Lemonbar.

# BATTERY
# =======
batteryStatus() {
  BATC=/sys/class/power_supply/BAT1/capacity
  BATS=/sys/class/power_supply/BAT1/status
  # prepend + or - depending on status
  test "`cat $BATS`" = "Charging" && echo -n '+' || echo -n '-'
  sed -n p $BATC
}

I would like the text to be red when below 20, yellow between 20-60 and green (or plain white) between 60-100.

I am very much a beginner with scripting and programming, but I've seen loops acting on arrays in javascript and ruby and I imagine there has to be an equivalent for bash scripting but I couldn't find anything through google or elsewhere.

Also if there is a more efficient way to grab this info, I welcome suggestions.

Last edited by felixculpa (2015-09-23 04:22:31)

Offline

#2 2015-09-23 00:32:59

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

Something like this:

# colours
red=$'\e[1;31m'
yel=$'\e[1;33m'
cyn=$'\e[1;36m'
end=$'\e[0m'

batt=/sys/class/power_supply/BAT0/
current=$(<"${batt}"/charge_now)
full=$(<"${batt}"/charge_full)
state=$(<"${batt}"/status)
number=$(( current * 100 / full )) 

if [[ $number -ge 0 ]] && [[ $number -le 20 ]]; then 
        colour="${red}"
    elif [[ $number -ge 21 ]] && [[ $number -le 60 ]]; then
        colour="${yel}"
    elif... etc
fi
printf '%s\n' "${colour}${number}${end}"

# edit: also, the volume functions are unnecessarily convoluted

volStatus=$(awk -F"[][]" '/dB/ { sub(/%/,""); print $2 }' <(amixer sget Master))
volLevel=$(awk -F"[][]" '/Front Left:/ { sub(/%/,""); print $2 }' <(amixer sget Master))

Awk does it all...


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#3 2015-09-23 01:03:13

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

Your best bet is if, elif, etc as bash case statements don't work on ranges of numbers.  Just for the hell of it I found a way to force bash's case statement to work on ranges of integers, but it is horribly ugly and wasteful:

eval $(cat <<EOF
case $value in
        $(echo {0..8}\| 9)    ) echo zeros ;;
        $(echo {10..18}\| 19) ) echo tens ;;
        $(echo {20..28}\| 29) ) echo twenties ;;
        $(echo {30..38}\| 39) ) echo thirties ;;
esac
EOF
)

Unless the number ranges are *huge* you'd be better off just typing out the numbers.  But again, the best bet would be if statements:

[[ $value -lt 10 ]] && echo zeros
[[ $value -gte 10 && $value -lt 20 ]] && echo tens
[[ $value -gte 20 && $value -lt 30 ]] && echo twenties
...

But note this still only works on integers - if you need real numbers you'd need to use `bc` or something similar, but as that level of precision is not needed, just chop any decimal off of value, then treat it as an integer, eg:

value=${value%%.*}

"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#4 2015-09-23 02:41:01

felixculpa
Member
From: Alberta, Canada
Registered: 2012-06-12
Posts: 252

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

Thank you, to you both. I'll have to study your examples closely to fully see and understand what they are doing and how it works.

The only other thing I would maybe also ask for, is an example of what you do to grab desktop info and how you display it. I have an incredibly simple thing for mine that you can gather from my script below.

Also if you can see how I can improve any part of the shell script, I would definitely be grateful. I use a netbook that is pretty limited in specs, so every extra ounce in performance helps.

lemonbar.sh in full:

#!/bin/sh

# WORKSPACES
# ==========
workSpaces() {
  bspcStatus=$(bspc control --get-status | cut -c 9-)
  printf %s "$bspcStatus"
}

# LOAD AVERAGE
# ============
loadAverage() {
  load=$(cat /proc/loadavg | cut -c -14)
  printf %s $load
}

# BATTERY
# =======
batteryStatus() {
  BATC=/sys/class/power_supply/BAT1/capacity
  BATS=/sys/class/power_supply/BAT1/status
  # prepend + or - depending on status
  test "`cat $BATS`" = "Charging" && echo -n '+' || echo -n '-'
  sed -n p $BATC
}

# VOLUME
# ======
volInfo() {
  volStatus=$(amixer get Master | tail -n 1 | cut -d '[' -f 3 | sed 's/]//g')
  volLevel=$(amixer get Master | awk '/Front Left:/ {print $5}' | tr -dc "0-9" | sed 's/%//g' )

  if [ "$volStatus" == "on" ]
    then
    printf %s "%{Fgreen}$volLevel%{F-}"
  else
    # If it is muted, make the font red
    printf %s "%{Fred}$volLevel%{F-}"
  fi
}

# CLOCK
# =====
dateTime() {
  clock=$(date '+%a - %b %d, %I:%M%P')
  printf %s "$clock"
}

# PIPE
# ====
while true; do
  echo "$(workSpaces) %{r}Batt: $(batteryStatus) \\ Vol: $(volInfo) \\ $(dateTime)"
  # Fetch info on computer and update on interval
  sleep 0.5;
done

Last edited by felixculpa (2015-09-23 02:43:45)

Offline

#5 2015-09-23 02:56:56

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

The only gratuitious processes are run in the volume function: see the edit to my post for a simpler awk solution.

You don't need the cat in the batteryStatus test: [[ $BATS = "Charging" ]] && ... || ... will do.

See also:


As you asked: my status bar script https://bitbucket.org/jasonwryan/shiv/s … dwm-status


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#6 2015-09-23 04:21:41

felixculpa
Member
From: Alberta, Canada
Registered: 2012-06-12
Posts: 252

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

Thanks again. There are some goldmines here.

Last edited by felixculpa (2015-09-23 04:21:56)

Offline

#7 2015-09-23 11:49:55

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

felixculpa wrote:

The only other thing I would maybe also ask for, is an example of what you do to grab desktop info and how you display it

I don't.  But I used to.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#8 2015-09-26 03:42:42

felixculpa
Member
From: Alberta, Canada
Registered: 2012-06-12
Posts: 252

Re: [SOLVED] Bash script ... acting on a range of values? (Lemonbar q.)

I meant workspace info instead of desktop, like virtual desktops and what have you. I didn't notice my mistake until later, however what you guys provided might ultimately be more useful.

Offline

Board footer

Powered by FluxBB