The following script is being used to generate the status line in wmii. I'm curious if there are faster/more efficient ways to find the various info I'm grabbing. I'm also a relative newbie when it comes to zsh (and shell scripting in general) so I'd also suspect that there are better ways to process some of the data.
#!/bin/zsh
cpu_freq=$(grep "cpu MHz" /proc/cpuinfo | sed 's/[\t ]*//g; s/cpuMHz://g')
cpu0=$(echo "scale=2;" `echo $cpu_freq | head -n 1 | tail -n 1` / 1000 | bc)
cpu1=$(echo "scale=2;" `echo $cpu_freq | head -n 2 | tail -n 1` / 1000 | bc)
cpu2=$(echo "scale=2;" `echo $cpu_freq | head -n 3 | tail -n 1` / 1000 | bc)
cpu3=$(echo "scale=2;" `echo $cpu_freq | head -n 4 | tail -n 1` / 1000 | bc)
stat=$(mpstat | tail -n 1 | tr -s ' ')
usr=$(echo $stat | cut -d ' ' -f 4)
nice=$(echo $stat | cut -d ' ' -f 5)
sys=$(echo $stat | cut -d ' ' -f 6)
cpu=$(echo $usr + $nice + $sys | bc)
memline=$(free | head -n 2 | tail -n 1 | tr -s ' ')
cached=$(echo $memline | cut -d ' ' -f 7)
free=$(echo $memline | cut -d ' ' -f 4)
cachedfree=$(echo $cached + $free | bc)
mem=$(echo "scale=3;" $cachedfree / 1000000 | bc)
network=$(nmcli nm | sed 's/ */\;/g' | cut -d \; -f 2 | tail -n 1)
tun0=$(ifconfig tun0 2>/dev/null)
vpn=$(if [[ -n $tun0 ]]; then; echo "(vpn:" $(cat /tmp/current-vpn)")"; else; echo ""; fi)
battery=$(acpi -b | sed 's/Battery 0: //; s/ until charged//; s/ remaining//; s/Charging/C/; s/Discharging/D/; s/Full, //; s/Unknown, //')
load=$(uptime | sed 's/.*://; s/,//g')
date=$(date +%a\ %b\ %d\ %H:%M)
echo -n $vpn $network '||' $mem GB '||' $cpu% '('$cpu0 $cpu1 $cpu2 $cpu3') ||' $load '||' $date '||' $battery
1 Answer 1
Extracting a column
It's a lot easier to extract columns from text using awk. Instead of this:
grep "cpu MHz" /proc/cpuinfo | sed 's/[\t ]*//g; s/cpuMHz://g'
This is shorter, and uses a single awk process instead of grep
+ sed
:
awk '/cpu MHz/ {print 4ドル}' /proc/cpuinfo
Extracting a line
This is a really awkward method to extract the 4th line:
echo $cpu_freq | head -n 4 | tail -n 1
This is simpler and better:
sed -ne 4p <<< "$cpu_freq"
Using arrays
Instead of getting the values of cpu0..cpu3
one by one by running separate command(s) for each, you can get it in one go:
cpus=($({ echo scale=2; awk '/cpu MHz/ {print 4ドル " / 1000"}' /proc/cpuinfo; } | bc))
Explanation:
- The
awk
command appends the" / 1000"
to the CPU frequency, so it's ready for piping tobc
- Pipe all lines (commands) to
bc
at once, and get all the output at once - Group the
echo scale=2
and theawk
forbc
by enclosing in{ ...; }
- Store the output of
bc
in an array
From this array, you can extract the individual CPU values
cpu0=${cpus[0]}
cpu1=${cpus[1]}
cpu2=${cpus[2]}
cpu3=${cpus[3]}
Next steps
I don't want to spoil all the fun for you :-) Following the techniques above, you should be able to extract the other values more efficiently (using fewer processes) in a similar fashion.