You are not logged in.

#1 2012-10-13 16:50:48

rix
Member
Registered: 2012-07-25
Posts: 238

[SOLVED] [Bash] How to completely unset value

Hi everyone,

I'm trying to improve my Bash Scripting skills, writing a script which shows up cpu temperature in Tmux statusbar.
I know I'd just set an "echo" through conditional statement but I'd also like that when temperature is under 75°C, *nothing* will shows up in the status.

Problem it's that my script always shows or the temperature or just and empty space.
I've also tried with the "continue" built-in statement but with no luck.

Sorry for such a noobish question and thanks in advance.
Also, every suggestions on how to improve the script will be obviously appreciated.

#!/usr/bin/env sh
# -----------------------------------------------------------------------------
# '$TMS/cpuTemp.sh'
# -----------------------------------------------------------------------------
# Set for debugging.
set -e
set -e pipefail

# Variables.
deps=(tmux, sensors)
runSens=$(sensors | tail -2 | awk '{print $2}' | cut -c 2,3)

# Are deps satisfied?
for entry in ${deps[*]}; do
    command -v ${deps[*]} > /dev/null

    [ "$?" -ne "0" ] && (echo -e "ER: \"Script ends with Exit Code \"$?\".\n
        Missing deps: this script requires \"${deps[*]}\" \
        in order to run.\""; exit "$?")
done

# Output.
# [ "${runSens}" -gt "75" ] && output="${runSens}" || unset output
output="${runSens}"

[ "$?" -ne 0 ] && \
    (echo -e "ER: \"Script ends with Exit Code \"$?\".\n
    Error occured\""; exit "$?") || \
    echo "${output}"
    
exit 0

Last edited by rix (2012-10-17 20:02:03)

Offline

#2 2012-10-15 00:00:24

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

Some points about your script.

1) You do a 'set -e' but then check all the $? exit statuses.  When you do 'set -e', your script exits if any command fails. Thus, $? will either be 0 or your script will have already exited before you can test it.

2) I believe you mean

set -o pipefail

but I don't believe you need this.

3) Putting the line

runSens=$(sensors | tail -2 | awk '{print $2}' | cut -c 2,3)

at the beginning of your script causes it to be executed there - before you do your dependency check. You should do the dependency check first, then do your pipeline.

4) You want to return the exit code of the command that failed; but you do an 'echo' then return $?.  What you are returning, then, is the status of the echo command and not the failed command.  If you want to return the status of your failed command, you have to save the status in some variable before you do echo, then return that as your desired status code.

5) Your for loop isn't doing what you think it is doing.  Specifically this line

command -v ${deps[*]} > /dev/null

should probably be

command -v "$entry" > /dev/null

6) If you don't want any output for temps < 75°C, then don't output anything. (See below.)

7) Since this output is going into a status bar, I would be less verbose upon failure. That's my personal taste; you, however, can do whatever you want.

Try this:

#!/bin/bash

for p in tmux sensors; do
    command -v "$p" > /dev/null && continue
    e=$?
    echo "no $p"
    exit $e
done

output=$(sensors | tail -2 | awk '{print $2}' | cut -c 2,3)
e=$?
if [ $e -ne 0 ]; then
    echo "??"
else
    [ ${output} -ge 75 ] && echo "${output}"
fi

exit $e

Last edited by rockin turtle (2012-10-15 00:14:24)

Offline

#3 2012-10-15 00:18:18

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

Re: [SOLVED] [Bash] How to completely unset value

In addition to rockin turtle's advice, I'd merely point out that awk can do all of the text processing:

output=$(sensors | tail -2 | awk '{print $2}' | cut -c 2,3)

can be rewritten as just:

output=$(sensors | awk '/CPU Temp/ {print +$2}'

(assuming that on your output the field really is $2).


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#4 2012-10-15 09:52:35

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

Thank so much to you both! Really appreciated.
I didn't think I'd made so many errors. Such a stupid I am.

I'm going to improve it.
Thanks again.


---
Edit:


@ rockin turtle:
Even your version leave the empty space in the status.
I've also tried with something like

for p in tmux sensors
    do
        output=$(sensors | awk '/temp1/ {print +$2}')
        if [ -n $output ]; then
            continue
        fi
done

just for testing but nothin changed. The space is always there. Even unsetting the variable.
I can't understand why and it drives me crazy.
Tmux Powerline has this functionality which works for me too. And it just use a continue statement.

And also I'm not sure about I understand the for cycle.


@ jasonwryan:
Just for reference, your statement obviously works I just have to replace

/CPU Temp/

with

/temp1/

in order to suite my need.

Thanks. smile

Last edited by rix (2012-10-15 20:01:45)

Offline

#5 2012-10-15 21:22:24

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

I'm not exactly sure what you are trying to accomplish.  Are you doing something like the following?

    set-option status-left '#(script)'

If the temperature is below 75, I don't understand if you don't want anything in your status bar, or you don't want a status bar at all.  Or is it something else?

About your for cycle, in your original post, you had what appeared to me to be an error. The code I posted corrected that error.  Incidentally, I really don't think you need that for loop at all. You could just take it out.

Offline

#6 2012-10-15 21:40:22

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

rockin turtle wrote:

I'm not exactly sure what you are trying to accomplish.  Are you doing something like the following?

    set-option status-left '#(script)'

Yes, but for the right status and with an external script.

set-option status-right '#[bg=#??????]#(/path/to/script.sh)'
rockin turtle wrote:

[...] If the temperature is below 75, [...] you don't want anything in your status bar [...]

That's it. Exactly.

Right now I have something like (i.e.):

volume[space]mail[space]temperature[space]clock  (<--- if temperature is above 75°C)
volume[space]mail[space][space][space]clock          (<--- if temperature is under 75°C)

I want to remove that space in such case, when I don't have a value (such as volume set to mute, zero mails, and so on).

rockin turtle wrote:

[...] About your for cycle, in your original post, you had what appeared to me to be an error. The code I posted corrected that error. [...]

And I really appreciate you suggestions I just don't completely understand your for cycle.

Thank so much. smile

Last edited by rix (2012-10-15 21:44:39)

Offline

#7 2012-10-15 21:45:40

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

Re: [SOLVED] [Bash] How to completely unset value

This would probably require an if... in the statusbar (which tmux may-or may not-support; you could always try it).

It would probably be a lot simpler to just move your temp reading to the right/left depending which way it reads, so the space is not visible when the temp < 75


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#8 2012-10-15 21:52:24

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

@ jasonwryan:
If statement already tried and doesn't work.
I found a "powerline" for Tmux (wich I've linked in my previous post) that use a continue statement (in the lib.sh file) wich do what I'm trying to accomplish.
I don't want the entire Powerline, just that function. And I want learn how to do that.

I don't think that moving the value in the right or left status would be useful for reach what I'm trying to do but thanks anyway for your reply.

Offline

#9 2012-10-15 22:54:56

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

Ok, you are not showing me everything. What exactly are you using for the XXX string below:

    set-option status-right XXX

In other words, how are you getting your volumn/mail/clock information.  Is it another script? Is it builtin to tmux?

The for loop is simple. My guess as to what is confusing you is the second line:

command -v "$p" > /dev/null && continue

It is a very common idiom in shell scripts, namely

cmd1 && cmd2

What bash does when it sees a construct like the above is it executes 'cmd1' then checks it's exit status $?.  If that status is 0, it then executes 'cmd2'.  If the first command fails ($? is non-zero) it won't execute 'cmd2'.

In the loop I posted, cmd1 is 'command -v "$p" > /dev/null' and cmd2 is 'continue'. If 'command -v "$p" > /dev/null' succeeds ($? == 0), bash executes 'continue' which causes it to skip the remainder of the loop and do the next iteration of the variable 'p'.

A similar common construct is:

cmd1 || cmd2

In this case, bash would execute cmd1, then execute cmd2 only if cmd1 FAILS.  That is, cmd2 will be executed only if cmd1's exit status is non-zero ($? != 0).

This doesn't need to be in a loop.  You can see I used the construct again:

[ ${output} -ge 75 ] && echo "${output}"

Here bash evaluates [ ${output} -ge 75 ], and if the exit status is 0, it then executes 'echo "${output}"'.  If [ ${output} -ge 75 ] evaluates to non-zero, then the echo command is not executed.

Offline

#10 2012-10-16 09:57:50

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

rockin turtle wrote:

Ok, you are not showing me everything. [...]

Relevant parts of:
$HOME/.tmux.conf

[...]

#if '[ -n "$DISPLAY" ]' 'source-file ~/.tmux/xStatBar'
#if '[ -z "$DISPLAY" ]' 'source-file ~/.tmux/statBar'
source-file ~/.tmux/statBar

N.b.: when I'll be ready and have the status completed, I'll use the first two (thanks to jasonwryan) statements instead of the last one.

$HOME/.tmux/statBar

[...]

set -g status-right '#[fg=brightyellow]#($HOME/.tmux/scr/vol.sh)  #[fg=brightgreen]#($HOME/.tmux/scr/mail.sh)  #[fg=brightcyan]#($HOME/.tmux/scr/upDt.sh)  #[fg=brightmagenta]#($HOME/.tmux/scr/net.sh)  #[fg=brightred]#($HOME/.tmux/scr/ram.sh)  #[fg=brightred]#($HOME/.tmux/scr/cpuTemp.sh)  #[fg=brightgreen]#($HOME/.tmux/scr/dt.sh)  #[fg=brightwhite]%H:%M'

[...]

And you already know what's about the cpuTemp.sh script


rockin turtle wrote:

[...] My guess as to what is confusing you is the second line: [...]

There's been a misunderstanding. smile
Many thanks for explanation but If you read my first post in this thread, you'll notice that I already know what "&&" and "||" mean.
What I'm not understanding is why you've make the "continue" following the "command" statement.


Again. I'd like have a Tmux status bar which when there's nothing to show up (as when we have mute volume, zero mails, zero updates, a connected wifi, ram and cpu temperature above some limits, even not in the same time) just don't show up anything (as Tmux Powerline does).
Not as it does right now, leaving an empty space for such values.

Last edited by rix (2012-10-16 10:01:09)

Offline

#11 2012-10-16 19:15:32

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

In bash, a 'continue' causes a for loop to jump to the next iteration of the loop.

I looked at that Tmux Powerline code. I think to do the same you would need one more script in addition to the 7 you have shown.

#!/bin/bash

sd=$HOME/.tmux/src

declare -A fg=(
	[vol]=brightyellow
	[mail]=brightgreen
	[upDt]=brightcyan
	[net]=brightmagenta
	[ram]=brightred
	[cpuTmp]=brightred
	[dt]=brightgreen
)

for s in "${!fg[@]}"; do
	output=$(${sd}/${s}.sh)
	[ -n "$output" ] && echo -n "#[fg=${fg[$s]}]$output  "
done

echo -n '[fg=brightwhite]=%H:%M'

This script is your master script. Save it as $HOME/.tmux/src/master.sh.  Now in your tmux.conf put

set -g status-right '#($HOME/.tmux/src/master.sh)'

You may have to change your other scripts as well.  They should output only the info you desire and should not output any newline characters.  So the cpuTemp script should be something like:

#!/bin/bash

output=$(sensors | awk '/CPU Temp/ {print $2}')
[ ${output%%.*} -ge 75 ] && echo -n "$output"

That's the entire script. Note the echo -n omits the newline. You would have to be more elaborate if you want it to output something if your sensors command failed i.e.

#!/bin/bash

output=$(sensors | awk '/CPU Temp/ {print $2}')
[ $? -ne 0 ] && { echo -n '!!'; exit; }
[ ${output%%.*} -ge 75 ] && echo -n "$output"

Any script for which you don't want any output, just don't output anything and it shouldn't show up in your status bar.

Last edited by rockin turtle (2012-10-16 20:30:41)

Offline

#12 2012-10-17 09:32:03

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

Many many many thanks. Finally it works! smile
Except the clock

[...]

echo -n '[fg=brightwhite]=%H:%M'

[...]

It makes Tmux shows up literally "=%H:%M".

Also, could you be just another little be patiente and explain me the following parts?

[...]

"${!fg[@]}"

[...]

and

[...]

${output%%.*}

[...]

Thanks again. smile

Offline

#13 2012-10-17 19:16:52

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

Maybe remove this line from master.sh:

echo -n '[fg=brightwhite]=%H:%M'

and change .tmux.conf to:

set -g status-right '#($HOME/.tmux/src/master.sh)[fg=brightwhite]=%H:%M'

There are 3 useful constructs for working with arrays in bash.

# given the following array
declare -A x=([a]=10 [b]=20 [c]=30)

"${x[@]}" # expands into the values of the array: "10 20 30"
"${!x[@]}" # expands into the indicies of the array: "a b c"
"${#x[@]}" # expands into the size of the array: 3

This works for both regular arrays (integer indicies) or for associative arrays (string indicies).

So, in this case

"${!fg[@]}"

expands into

vol mail upDt net ram cpuTmp dt

see http://mywiki.wooledge.org/BashFAQ/005

"${output%%.*}" is parameter expansion.  When you do

output=$(sensors | awk '/CPU Temp/ {print $2}')

on my machine, the value of 'output' is something like '+29.2°C'.  So if you then did

[ $output -ge 75 ] && echo -n "$output"

bash would complain "integer expression required" or something like that. The reason for this is that bash considers '+29.2°C' to be a string and not an integer.  In order to compare if this value is > 75, you have to convert this string into something bash will intrepret as an integer.  In other words, you have to remove the '.2°C' from the end of the string.

So the construct "${x%%.*}" takes a variable 'x' containing a string, and removes the longest substring starting with a '.' from the END of 'x'.  In this case, it would remove the '.2°C'.

A similar construct is "${x##*.}".  This construct would remove the longest substring ending in a '.' from the start of the sting.  In our case "${output##*.} would expand into '2°C'. See http://www.gnu.org/software/bash/manual … -Expansion. Specifically, the parts about

${parameter#word}
${parameter##word}

and

${parameter%word}
${parameter%%word}

Last edited by rockin turtle (2012-10-17 19:33:07)

Offline

#14 2012-10-17 19:56:49

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

Re: [SOLVED] [Bash] How to completely unset value

...or you could just use

output=$(sensors | awk '/CPU Temp/ {print +$2}')

which outputs 29 smile


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#15 2012-10-17 20:01:01

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

There's always something to learn!
Thanks. A lot. smile


---
Edit:
I think someone is fallen in love with Awk. big_smile
And I'm going to learn it instead. smile

By the way, I got the point. Thanks to you both. wink


---
Edit:
I'm sorry, one last thing, I promise. big_smile

Am I already a noob or there isn't a way to also set a show order for those scripts (i.e.: first=clock; second=date; third=volume, and so on)?

Last edited by rix (2012-10-17 20:11:45)

Offline

#16 2012-10-17 22:00:12

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] [Bash] How to completely unset value

I thought that might be a problem after I posted.

You could change

for s in "${!fg[@]}"; do
	output=$(${sd}/${s}.sh)
	...

to

for s in vol mail upDt net ram cpuTmp dt; do
	output=$(${sd}/${s}.sh)
	...

and put them in whatever order you want.

Offline

#17 2012-10-18 09:04:54

rix
Member
Registered: 2012-07-25
Posts: 238

Re: [SOLVED] [Bash] How to completely unset value

Ok, I'm already a noob. big_smile

Thank so much rockin turtle.

Offline

Board footer

Powered by FluxBB