脚本笔记8/27/2026
nvidia-fan-control.sh
来源文件:
nvidia-fan-control.sh
已自动脱敏 1 处敏感信息。
bash
#!/bin/bash
# vim: set foldenable foldmethod=marker ts=4 sw=4:
# License Info {{{1
# Fan Control Script w/ Fan Curve
# Copyright (C) 2019 Barry Van Deerlin#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
##### Configurable Settings ##### {{{1
# FanControl Configuration Path {{{1
[REDACTED_SENSITIVE_LINE]
# Default Fan Speed Setting {{{1
defaultSpeed=60
# Persistent Fan Curve Refresh Interval {{{1
refresh=30
# Fan Curve Settings {{{1
# Day Curve Start Time (24 Hour Time)
dCurveStart=12
# Night Curve Start Time (24 Hour Time)
nCurveStart=23
# Night Curve Enable/Disable (true/false)
# Disable if you don't want seperate day and night curves
nCurveEnabled=true
# Fan Curve Temperature Thresholds (In Celsius) {{{2
# The temperature threshold is the temperature at which the the script
# applies a different fan curve point. When Adding Temperature Thresholds
# you must also add curve points.
# There must always be one less temperature threshold (Excluding MAXTHRESHOLD)
# then there is curve points for the script to work.
MAXTHRESHOLD=80 # Fans will run at 100% if hotter than this temperature
tempThresh[0]=70 # <-- Apply curve[0] if hotter than
tempThresh[1]=60 # <-- Apply curve[1] if hotter than
tempThresh[2]=50 # <-- Apply curve[2] if hotter than
tempThresh[3]=40 # <-- Apply curve[3] if hotter than
tempThresh[4]=30 # <-- Apply curve[4] if hotter than
# """ Apply curve[5] if cooler than
# Fan Curve Points {{{2
# The curve point is the Fan Speed Percentage applied at a given temperature
# threshold. When Adding Curve Points you must also add temperature thresholds.
# There must always be one less temperature threshold (Excluding MAXTHRESHOLD)
# then there is curve points for the script to work properly.
# Day Curve Night Curve
dCurve[0]=70 nCurve[0]=60
dCurve[1]=60 nCurve[1]=50
dCurve[2]=50 nCurve[2]=40
dCurve[3]=40 nCurve[3]=30
dCurve[4]=30 nCurve[4]=20
dCurve[5]=20 nCurve[5]=0
##### End Configurable Settings ##### {{{1
# Export Display (For Headless Use) {{{1
export DISPLAY=':0'
# Get Number of Connected GPUs {{{1
numGPUs=$(nvidia-smi --query-gpu=count --format=csv,noheader -i 0)
# Function to enable manual fan control state on first run {{{1
initFCS()
{
FanControlStates=($(nvidia-settings -q GPUFanControlState | grep 'Attribute' | awk -vFS=': ' -vRS='.' '{print $2}'))
for i in ${FanControlStates[@]}; do
if [ $i -eq 0 ]; then
nvidia-settings -a "GPUFanControlState=1" > /dev/null 2>&1
echo "Fan Control State Enabled"
break
fi
done
}
# Function that applies Fan Curve {{{1
runCurve()
{
# Get GPU Temperature and Current FanSpeed
IFS=$'\n'
gputemp=($(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader))
currentSpeed=($(nvidia-smi --query-gpu=fan.speed --format=csv,noheader | awk '{print $1}'))
unset IFS
[ $nCurveEnabled ] && cTime=$(date +'%H') || cTime=$dCurveStart # Get the time
# Checks time to apply day or night curve
[ $cTime -lt $dCurveStart -o $cTime -ge $nCurveStart ] && curve=("${nCurve[@]}") || curve=("${dCurve[@]}")
# Loop through each GPU
for i in $(seq 0 $((numGPUs-1))); do
speed=100
# Set speed to appropriate value from curve
if [ ${gputemp[$i]} -lt $MAXTHRESHOLD ]; then
cPoint=$((${#curve[@]}-1))
for c in $(seq 0 $cPoint); do
index=$c
case "$c" in
$cPoint)
comparison=-lt
index=$((c-1))
;;
*)
comparison=-ge
;;
esac
[ ${gputemp[$i]} $comparison ${tempThresh[$index]} ] && { speed=${curve[$c]}; break; }
done
fi
# Apply fan speed if speed has changed
[ $speed -lt $((currentSpeed[i]-1)) -o $speed -gt $((currentSpeed[i]+1)) ] && nvidia-settings -a "[fan:$i]/GPUTargetFanSpeed=$speed"
done
}
# Function that gets GPU Fan Stats and displays them {{{1
getInfo()
{
IFS=$'\n'
# Retrieve GPU Names, Fan Speed, and Temperature
query=($(nvidia-smi --query-gpu=name,fan.speed,temperature.gpu --format=csv,noheader))
# Retrieve GPU Fan RPM
query_rpm=($(nvidia-settings -q GPUCurrentFanSpeedRPM | grep "fan:" | awk -F ': ' -vRS='.' '{print $2}'))
# Summary format
# Nvidia Fan Info
# | Card | | Fan Speed | | Fan RPM | | GPU Temp |
# Geforce GTX 1080 Ti 50% 1600 53°
# Print out Header
printf "Nvidia Fan Info\n| Card |\t\t| Fan Speed |\t| Fan RPM |\t| GPU Temp |\n"
# Loop through GPUs to compile summary
for i in $(seq 0 $((numGPUs-1))); do
card=$(awk -F ', ' '{print $1}' <<< ${query[$i]})
fan_speed=$(awk -F ', ' '{print $2}' <<< ${query[$i]} | awk '{print $1}')
fan_rpm=${query_rpm[$i]}
temp=$(awk -F ', ' '{print $3}' <<< ${query[$i]})
printf "%s: %s\t %s%%\t %s\t %s°\n" $i $card $fan_speed $fan_rpm $temp
done
unset IFS
}
# Parse and Execute Arguments passed to script {{{1
case "$1" in
# Set Fan Speed for all GPU Fans {{{2
set|s)
case "$2" in
# Enable Fan Curve (Use with Cron)
curve|c) speed="curve" ;;
# Set Speed to Default
default|d) speed=$defaultSpeed ;;
# Set Speed to Max
max|m|100) speed=100 ;;
# Turn Fans Off
off) speed=0 ;;
# Set Fan Speed Manually
[0-9]|[1-9][0-9]) speed=$2 ;;
# Improper Input Given
*) echo "Usage: $0 $1 {# Between 0 - 100|d (default)|m (max)|off|curve}"; exit 2 ;;
esac
case "$speed" in
curve)
echo curve > $fanConfig # Change Configuration to Curve
$0 curve # Run Fan Curve
;;
*)
echo manual > $fanConfig # Enabling Manual Control and Disabling Fan Curve
initFCS
nvidia-settings -a "GPUTargetFanSpeed=$speed"
;;
esac
;;
# For testing Individual GPU Fan Settings {{{2
dx)
# Test if Proper Input was given
# Is input $2 a valid GPU index? Is input $3 a number that is less than or equal to 100?
re='^[0-9]{,2}$'
[ $# -eq 3 ] && [[ $2 =~ $re && $2 -lt $numGPUs ]] && [[ $3 =~ $re || $3 -eq 100 ]] \
&& nvidia-settings \
-a "[gpu:$2]/GPUFanControlState=1" \
-a "[fan:$2]/GPUTargetFanSpeed=$3"
[ $? -ne 0 ] && { echo "Usage: $0 $1 gpuIndex FanSpeed Between 0 - 100"; exit 2; }
;;
# Applies Fan Curve (For use with cron) {{{2
curve|c)
# Checks if Configuration File exists and create it if it doesn't
[ ! -f $fanConfig ] && echo "curve" > $fanConfig
# Run fan curve if configuration is set to curve
case "$(cat $fanConfig)" in
curve)
initFCS
runCurve
;;
esac
;;
# Applies Persistant Fan Curve (For use without cron) {{{2
pcurve|pc)
echo "pcurve" > $fanConfig
initFCS
# Run while configuration is set to pcurve
while [ "$(cat $fanConfig)" == "pcurve" ]; do
runCurve
sleep $refresh
done
;;
# Display GPU Fan and Temp Status {{{2
info|i)
getInfo
;;
# Display Version Info {{{2
--version|-v)
echo "$0 v0.1 Copyright (C) 2019 Barry Van Deerlin"
;;
# Incorrect Usage {{{2
*)
echo "Usage: $0 {set|dx(diagnose)|curve|pcurve|info)}"
exit 2
esac
# Exit {{{1
exit 0