You are not logged in.
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
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...
Offline
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
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
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
Offline
Thanks again. There are some goldmines here.
Last edited by felixculpa (2015-09-23 04:21:56)
Offline
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
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