Bash script have problems depending on desktop environment. How to fix this

bashlinuxshell-scriptUbuntu

System: Ubuntu 16.04.1 Xenial Xerus

Hi,

I'm having a strange problem with my bash script used to control the GPU fan speed.

This script changes the GPU fan speed if the GPU passes to another temperature range.

Code:

#!/bin/bash

interval=5

while true; do

current_temp=`nvidia-settings -query GPUCoreTemp| grep gpu | perl -ne 'print $1 if /GPUCoreTemp.*?: (\d+)./;'`

if (("$current_temp" < 45)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=40

elif (("$current_temp" > 45)) && (("$current_temp" < 60)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=50

elif (("$current_temp" > 60)) && (("$current_temp" < 65)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=60

elif (("$current_temp" > 65)) && (("$current_temp" < 70)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=70

elif (("$current_temp" > 70)) && (("$current_temp" < 75)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=80

elif (("$current_temp" > 75)); then
    nvidia-settings -a [gpu:0]/GPUFanControlState=1 -a [fan:0]/GPUTargetFanSpeed=100

fi
sleep "$interval"
done

In Unity DE, Gnome and KDE, this script works flawlessly using ./nvautofan.sh, but this script presents an error if I call the same command in XFCE4 (using bash -x ./nvautofan.sh for debugging):

Gnome debug output (expected):

+ interval=5
+ true
++ perl -ne 'print $1 if /GPUCoreTemp.*?: (\d+)./;'
++ grep gpu
++ nvidia-settings -query GPUCoreTemp
+ current_temp=37 # Proper output
+ (( 37 < 45 ))
+ nvidia-settings -a '[gpu:0]/GPUFanControlState=1' -a '[fan:0]/GPUTargetFanSpeed=40'

Attribute 'GPUFanControlState' (LINUX-RIG:0[gpu:0]) assigned value 1.

Attribute 'GPUTargetFanSpeed' (LINUX-RIG:0[fan:0]) assigned value 40.

+ sleep 5
# ...

nvidia-settings -query GPUCoreTemp Output (Gnome)

Attribute 'GPUCoreTemp' (LINUX-RIG:0.0): 39.
    'GPUCoreTemp' is an integer attribute.
    'GPUCoreTemp' is a read-only attribute.
    'GPUCoreTemp' can use the following target types: X Screen, GPU.
Attribute 'GPUCoreTemp' (LINUX-RIG:0[gpu:0]): 39.
    'GPUCoreTemp' is an integer attribute.
    'GPUCoreTemp' is a read-only attribute.
    'GPUCoreTemp' can use the following target types: X Screen, GPU.

XFCE4 debug output (non-functional)

+ interval=5
+ true
++ nvidia-settings -query GPUCoreTemp
++ grep gpu
++ perl -ne 'print $1 if /GPUCoreTemp.*?: (\d+)./;'
+ current_temp= # An error appeared here
+ ((  < 45 ))
nvautofan.sh: line 15: ((: < 45: syntax error: operand expected (error token is "< 45")
+ ((  > 45 ))
nvautofan.sh: line 17: ((: > 45: syntax error: operand expected (error token is "> 45")
+ ((  > 60 ))
nvautofan.sh: line 19: ((: > 60: syntax error: operand expected (error token is "> 60")
+ ((  > 65 ))
nvautofan.sh: line 21: ((: > 65: syntax error: operand expected (error token is "> 65")
+ ((  > 70 ))
nvautofan.sh: line 23: ((: > 70: syntax error: operand expected (error token is "> 70")
+ ((  > 75 ))
nvautofan.sh: line 25: ((: > 75: syntax error: operand expected (error token is "> 75")
+ sleep 5
# ...

nvidia-settings -query GPUCoreTemp Output (XFCE)

Attribute 'GPUCoreTemp' (LINUX-RIG:0.0): 38.
    'GPUCoreTemp' is an integer attribute.
    'GPUCoreTemp' is a read-only attribute.
    'GPUCoreTemp' can use the following target types: X Screen, GPU.

So, facing this problem, I tried to workaroud this using sh ./nvautofan.sh, but I discovered an error that creates files in my script folder (script continues non-functional):

+ interval=5
+ true
+ nvidia-settings -query GPUCoreTemp
+ grep gpu
+ perl -ne print $1 if /GPUCoreTemp.*?: (\d+)./;
+ current_temp=
nvautofan.sh: 15: nvautofan.sh: cannot open 45: No such file
+ 
nvautofan.sh: 15: nvautofan.sh: : Permission denied
+ 
nvautofan.sh: 17: nvautofan.sh: : Permission denied
+ 
nvautofan.sh: 19: nvautofan.sh: : Permission denied
+ 
nvautofan.sh: 21: nvautofan.sh: : Permission denied
+ 
nvautofan.sh: 23: nvautofan.sh: : Permission denied
+ 
nvautofan.sh: 25: nvautofan.sh: : Permission denied
+ sleep 5
# ...

How can I solve this problem in order to execute this script in XFCE properly?

Thank you.

Best Answer

The issue is that (for whatever reason) the output from nvidia-settings -query GPUCoreTemp under XFCE does not contain the string gpu. It only shows you the first set of lines compared with the output from the same command run under GNOME. This means current_temp will be empty and that the arithmetic expansions later will fail.

Running the script under sh will not fix this.

The following bash script will instead pick out the number at the end of the first line of output and use that as the current temperature (Edit: modified to use another command after comments).

#!/bin/bash

function set_fan_speed {
    local speed="$1"

    nvidia-settings -a "[gpu:0]/GPUFanControlState=1" \
        -a "[fan:0]/GPUTargetFanSpeed=$speed"
}

interval=5

while true; do
    current_temp="$( nvidia-smi -a |
      grep -F 'GPU Current Temp' | awk '{ print $(NF-1) }' )"

    if [[ -z "$current_temp" ]]; then
        echo "Something isn't right, current_temp is empty" >&2
        exit 1
    fi

    if   (( current_temp < 45 )); then set_fan_speed 40
    elif (( current_temp < 60 )); then set_fan_speed 50
    elif (( current_temp < 65 )); then set_fan_speed 60
    elif (( current_temp < 70 )); then set_fan_speed 70
    elif (( current_temp < 75 )); then set_fan_speed 80
    else                               set_fan_speed 100
    fi

    sleep "$interval"
done

I put the long command in a function for readability and removed unnecessary arithmetic tests. I also inserted a sanity check for current_temp.

A future improvement of this script may include not touching the fan speed at all if it doesn't need to be modified. Keeping track of the current fan speed and not updating it in set_fan_speed if not needed would be the obvious way to go.

Note: I do not actually know if the nvidia-settings call in the set_fan_speed function works. It may well be that [gpu:0]/ should be removed or that some other modification needs to be done for the script to run under both GNOME and XFCE. My solution at least takes care of the primary problem of parsing the temperature.

Related Question