<html>
<head>
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>Hi Brad,</p>
<p>I've done up a pure bash (other than smartctl and sudo) version
of this with a few extra features.</p>
<p>You can download it from
<a class="moz-txt-link-freetext" href="http://www.sbts.com.au/files/drive-age.sh">http://www.sbts.com.au/files/drive-age.sh</a></p>
<p>But here it is in text form</p>
<p>There are a few long lines that will probably wrap in you mail
software so either download it or fix those before running<br>
Also, in the HELP() function the <------> are tabs. please
replace before execution<br>
<br>
There are various things that could be shrunk into either less
lines, or less verbose code.<br>
eg: the declare's at the top of the script could be a single
declare with multiple Variable Names;<br>
Also there are uses of "if then" statements that could be reduced
to && etc.<br>
I've left it as is to hopefully make it easier for you to follow<br>
</p>
<p>#!/bin/bash<br>
<br>
Init() {<br>
local Idx=0;<br>
declare -g -a Device;<br>
declare -g -a Model;<br>
declare -g -a Serial;<br>
declare -g -a Hours;<br>
declare -g -a Temperature;<br>
declare -g -a TemperatureUnit;<br>
<br>
declare -g SMARTCTL='/usr/sbin/smartctl'<br>
declare -g SUDO<br>
[[ ! -u $SMARTCTL ]] && { # "no setUID so try using
sudo"<br>
read -rst5 SUDO < <( which sudo )<br>
[[ -x "$SUDO" ]] && $SUDO -v -p 'Please enter your
[sudo] password so we can run "smartctl -x": '<br>
read -rst5 SMARTCTL < <( $SUDO which smartctl )<br>
[[ ! -x $SMARTCTL ]] && { echo "We don't seem to
be able to run 'smartctl' ($SMARTCTL)"; exit 9; }<br>
}<br>
}<br>
<br>
Scan() {<br>
echo -n 'Scanning drives '<br>
for Dev in /dev/sd? ; do<br>
local Id='' Name='' Flags='' Value='' Worst='' Thresh=''
Fail='' Raw='' J='';<br>
Device[$Idx]="$Dev"<br>
echo -n "."<br>
while read -rst10 Id Name Flags Value Worst Thresh Fail
Raw J; do<br>
[[ "$Id" == 'Device' ]] && [[ "$Name" ==
'Model:' ]] && {<br>
Model[$Idx]="${Flags} ${Value} ${Worst} ${Thresh}
${Fail} ${Raw} ${J}";<br>
continue;<br>
}<br>
[[ "$Id" == 'Serial' ]] && [[ "$Name" ==
'Number:' ]] && {<br>
Serial[$Idx]="${Flags} ${Value} ${Worst} ${Thresh}
${Fail} ${Raw} ${J}";<br>
continue;<br>
}<br>
[[ "$Name" == 'Power_On_Hours' ]] && {<br>
Hours[$Idx]="$Raw";<br>
continue;<br>
}<br>
[[ "$Id" == 'Lifetime' ]] && \<br>
[[ "$Name" == 'Min/Max' ]] && \<br>
[[ "$Flags" == 'Temperature:' ]] && {<br>
Temperature[$Idx]="$Value";<br>
TemperatureUnit[$Idx]="$Worst";<br>
continue;<br>
}<br>
done < <( $SUDO $SMARTCTL -x $Dev)<br>
(( Idx++ ));<br>
done<br>
eval declare -g -a Index=( {0..$(( ${#Device[@]} -1 ))} ); #
this just sets a default index order<br>
echo " : Done"<br>
}<br>
<br>
DisplayLines() { # $1 is format, remaining args are values<br>
local fmt="$1"; shift<br>
local I=0 maxI=${#Device[@]} J=0;<br>
while (( I<maxI )); do<br>
J=${Index[$I]}<br>
local Hrs=${Hours[$J]}<br>
local Y=0 D=0 H=0<br>
(( Y = Hrs/(365*24) ))<br>
(( H = Hrs % (365*24) ))<br>
(( D = H/24 ))<br>
(( H = H%24 ))<br>
printf "$fmt" "${Device[$J]}" "${Model[$J]}" $Y $D $H
"${Temperature[$J]}" "${TemperatureUnit[$J]}"<br>
(( I++ ))<br>
done<br>
}<br>
<br>
Display(){<br>
DisplayLines "%-8s - %-30s - %2u Years %3u Days %2u Hours -
Temperature (min/max) %s %s\n"<br>
}<br>
<br>
Display_Table(){<br>
local
L='--------------------------------------------------------------'<br>
local I=${#Device[@]};<br>
printf " %-8.8s %-36.36s
,-%5.5s---%4.4s---%5.5s-,-%11.11s-,\n" '' '' "$L" "$L" "$L" "$L"<br>
printf ",-%-8.8s-,-%-36.36s-| %5s %4s %5s | %11.11s |\n"
"$L" "$L" '' 'Age' '' ' (min/max) '<br>
printf "| %-8s | %-36s | %5s | %4s | %5s | %11.11s |\n"
'Device' 'Model' 'Years' 'Days' 'Hours' 'Temperature'<br>
printf
"|-%-8.8s-|-%-36.36s-|-%5.5s-|-%4.4s-|-%5.5s-|-%11.11s-|\n" "$L"
"$L" "$L" "$L" "$L" "$L"<br>
DisplayLines "| %-8s | %-36.36s | %5u | %4u | %5u | %9s %1.1s
|\n"<br>
printf
"'-%-8.8s-'-%-36.36s-'-%5.5s-'-%4.4s-'-%5.5s-'-%11.11s-'\n" "$L"
"$L" "$L" "$L" "$L" "$L"<br>
}<br>
<br>
Build_Index_Sorted() { # $1 = Reverse Sort Order [true|false]<br>
[[ ${1:-up} == up ]] && Reverse=false;<br>
[[ ${1:-up} == down ]] && Reverse=true;<br>
local maxI=${#Index[@]}; #(( maxI -- )) # adjust for zero
offset<br>
unset Index; declare -g -a Index;<br>
local I=0;<br>
while (( I<maxI )); do<br>
local J=0 current=0<br>
while [[ "z${Index[@]}z" =~ "${current}" ]]; do ((
current++ )); done # find first Item not in Index<br>
while (( J<maxI )); do<br>
[[ "z"${Index[@]}"z" =~ "${J}" ]] && { (( J++
)); continue; }<br>
if $Reverse; then<br>
! (( ${Hours[$J]} <= ${Hours[$current]} ))
&& (( current = J ));<br>
else<br>
(( ${Hours[$J]} <= ${Hours[$current]} ))
&& (( current = J ));<br>
fi<br>
(( J++ ))<br>
done<br>
Index[$I]=$current;<br>
(( I++ ))<br>
done<br>
}<br>
<br>
HELP() { # NOTE the <------> is a tab. please replace before
execution<br>
cat <<-EOF<br>
<------>usage: ${0##*/} [-n | -t]<br>
<------> -L|l : Line based output<br>
<------> -T|t : Table based output<br>
<------> -s : Sort Youngest to Oldest<br>
<------> -S : Sort Oldest to Youngest<br>
<------>EOF<br>
}<br>
<br>
Main() {<br>
Init<br>
Scan<br>
[[ "$@" =~ -[s] ]] && Build_Index_Sorted up<br>
[[ "$@" =~ -[S] ]] && Build_Index_Sorted down<br>
[[ "$@" =~ -[tT] ]] && { Display_Table; return; }<br>
[[ "$@" =~ -[lL] ]] && { Display; return; }<br>
HELP<br>
}</p>
<p>Main "$@"<br>
<br>
</p>
<br>
<div class="moz-cite-prefix">On 08/05/17 08:40, Brad Campbell wrote:<br>
</div>
<blockquote
cite="mid:595b9979-2ca0-cd11-daa3-27219f31603b@fnarfbargle.com"
type="cite">#!/bin/bash
<br>
declare -a ARR
<br>
CNT=0
<br>
echo -n Scanning drives.
<br>
for i in /dev/sd? ; do
<br>
echo -n "."
<br>
SMART=$(smartctl -x $i)
<br>
hrs=$(echo "$SMART" | grep Power_On_Hours | awk '{print $8}' |
egrep -v '[[:alpha:]]')
<br>
[ -z "$hrs" ] && hrs=$(echo "$SMART" | grep 'Power-on
Hours' | awk '{print $4}')
<br>
[ -z "$hrs" ] && hrs=$(echo "$SMART" | egrep '^# 1' |
cut -c 60- | awk '{print $1}')
<br>
model="$(echo "$SMART" | grep 'Device Model:' | cut -f2 -d':'
| xargs)"
<br>
if [ -n "$hrs" ] ; then
<br>
ARR[$CNT]="$hrs $i $model"
<br>
CNT=$((CNT+1))
<br>
fi;
<br>
done
<br>
echo Done scanning
<br>
IFS=$'\n' sorted=($(sort -n <<<"${ARR[*]}"))
<br>
for i in ${sorted[*]} ; do
<br>
hrs=`awk '{print $1}' <<< $i`
<br>
dev=`awk '{print $2}' <<< $i`
<br>
model=`cut -f3- -d" " <<< $i`
<br>
Y=$((hrs/(365*24)))
<br>
hrs=$((hrs%(365*24)))
<br>
D=$((hrs/24))
<br>
hrs=$((hrs%24))
<br>
echo $dev" - "$model" - "$Y years $D days $hrs hours
<br>
done
<br>
</blockquote>
<br>
<div class="moz-signature">-- <br>
<style>
div.sig {
border: 1px solid black;
height: auto;
float: left;
padding: 1em;
}
span.left {
width: 4em;
float: left;
}
span.pulseit {
-webkit-animation: mymove 1s infinite; /* Chrome, Safari, Opera */
animation: pulse 2s infinite;
}
@keyframes pulse { 50% {font-size: 0.9em;} }
</style>
Regards<br>
David Godfrey<br>
<br>
<div class="sig">
<br>
<span class="left"> mb:<br>
<span class="pulseit">chat:</span> </span> <span
style="float: right;"> 0437 286 200<br>
with <em>dcg_mx</em> at <a
href="http://matrix.to/#/#sbts:matrix.org">#sbts:matrix.org</a>
<p style="font-size:smaller;">Chat is via matrix.org.<br>
There are clients available for All Operating Systems and
Hardware devices.<br>
Including Linux, Android, Windows, Mac, iOS<br>
I'd recommend the multiplatform RIOT client as the best
starting point.<br>
with RIOT web the easiest on any PC </p>
</span>
</div>
</div>
</body>
</html>