You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加速zsh shell脚本中top命令的调用速度?

优化Oh-My-Zsh提示符脚本的运行速度

我在Oh-My-Zsh的提示符里运行一个脚本,用来展示磁盘占用、CPU负载、内存使用和电池状态,输出效果是这样的:

(68% disk used) (1.48[16] cores @ 8.7%) (16G used / 16G) 100% 🔌

但每次回车后要等好几秒才显示提示符,实在烦人。我知道top -l 1 -s 0单次运行连0.25秒都不到,肯定是脚本里重复调用了它,而且df、sysctl、pmset这些命令也被多次调用,拖慢了速度。原脚本如下:

#!/bin/zsh

toplist=(top -l 1 -s 0)
sysctllist=(sysctl hw)
pmsetlist=(pmset -g batt)
storagelist=(df -h)

availablestorage=$($storagelist | grep "/dev/disk1s2" | awk '{print $2}' | sed 's/Gi//')
availablestorage=$((availablestorage * 1.073741824))
usedstorage=$($storagelist | grep "/" | awk '{print $3}' | grep "Gi" | sed 's/Gi//' | awk '{ sum += $1 } END { print sum }')
usedstorage=$((usedstorage * 1.073741824))
storagepercentused=$((100 * (usedstorage / availablestorage)))
storagepercentusedrounded=$( echo "($storagepercentused)/1" | bc)

loadavg=$($toplist | grep 'Load Avg' | awk '{print $3, $4, $5}' | tr -d , | awk '{print $2}')
ncpu=$($sysctllist | grep ".ncpu" | grep -o -E '[1-9]+')
percentidle=$($toplist | grep 'CPU usage:' | awk '{print $3, $5, $7}' | tr -d , | tr -d % | awk '{print $3}')
memoryfree=$($toplist | grep 'PhysMem' | awk '{print $2}')
totalmemory=$($sysctllist | grep .memsize | grep -oE '[1-9]+')
batterypercent=""$($pmsetlist | grep "%" | awk '{print $3}' | tr -d \;)"%"
power=""
if ($pmsetlist | grep "Battery Power") >> /dev/null then
    power="🔋"
elif ($pmsetlist | grep "AC Power") >> /dev/null then
    power="🔌"
fi

echo "($storagepercentusedrounded%% disk used) ("$loadavg"["$ncpu"] cores @ "$(printf '%.*f
' 1 $((100 - $percentidle)))"%%) ("$memoryfree" used / "$(($totalmemory / 1024 / 1024 / 1024))"G)" %F{white}$batterypercent $power

核心问题与优化方案

你的脚本慢的根源是重复调用外部命令:top被调用了3次,df、sysctl、pmset各被调用了2次。每次启动外部进程都有额外开销,积少成多就导致了延迟。

优化思路是:每个外部命令只执行一次,把输出存入变量,后续直接从变量中提取所需信息;同时简化文本处理流程,减少不必要的管道和命令调用。

优化后的脚本:

#!/bin/zsh

# 仅调用一次所有外部命令,将输出存入变量复用
top_output=$(top -l 1 -s 0)
sysctl_output=$(sysctl hw)
pmset_output=$(pmset -g batt)
df_output=$(df -h)

# 用单段awk完成磁盘信息的提取、求和与百分比计算
storage_percent=$(echo "$df_output" | awk '
    /\/dev\/disk1s2/ { avail = $2; sub(/Gi/, "", avail) }
    /\// && $3 ~ /Gi/ { used += $3; sub(/Gi/, "", $3) }
    END {
        avail_gb = avail * 1.073741824
        used_gb = used * 1.073741824
        printf "%.0f", 100 * (used_gb / avail_gb)
    }')

# 从单次top输出中提取所有需要的CPU、内存、负载信息
load_avg=$(echo "$top_output" | awk '/Load Avg/ { gsub(/,/, "", $4); print $4 }')
cpu_idle=$(echo "$top_output" | awk '/CPU usage:/ { gsub(/[%|,]/, "", $7); print $7 }')
mem_used=$(echo "$top_output" | awk '/PhysMem/ { print $2 }')

# 从单次sysctl输出中提取CPU核心数和总内存
cpu_cores=$(echo "$sysctl_output" | awk '/hw.ncpu/ { print $2 }')
total_mem=$(echo "$sysctl_output" | awk '/hw.memsize/ { print int($2 / 1024 / 1024 / 1024) }')

# 单次提取电池百分比和供电状态
battery_percent=$(echo "$pmset_output" | awk '/%/ { gsub(/;/, "", $3); print $3 "%"}')
power_icon=$(echo "$pmset_output" | awk '/Battery Power/ { print "🔋" } /AC Power/ { print "🔌" }')

# 拼接最终输出
echo "($storage_percent% disk used) ($load_avg[$cpu_cores] cores @ $(printf "%.1f" $((100 - cpu_idle)))%) ($mem_used used / $total_memG) %F{white}$battery_percent $power_icon"

关键优化点

  1. 减少外部命令调用:所有系统命令只执行一次,避免重复启动进程的开销
  2. 简化文本处理:用单段awk替代多管道的grep+sed+awk组合,减少进程启动次数
  3. 合并逻辑判断:电池状态直接用awk完成匹配输出,替代原来的分支判断+重复调用pmset
  4. 简化单位转换:总内存计算直接在awk中完成,避免后续的shell算术运算

内容的提问来源于stack exchange,提问作者Jacob Jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:35:07