Skip to content.
Joe Heaton's Webzone
🥐 ☕
Online since 2011

My terminal login message

Following on from bashrc, here is a snapshot and explaination of my .motd

function prx {
    local rand=$( tr -dc 'a-fA-F0-9' < /dev/urandom | head -c6 )
    printf "\r$(command -v bashColor >/dev/null && bashColor sf $rand)"
    printf "~\e[0m"

Fun colours first, using the bashColor function from my .bashrc we pull random alphanumeric characters within the hexidecimal range and feed that to bashColor to return a terminal color escape sequence. The last line prints the preferred message prefix and the reset-formatting escape code.

function print_iostat {
    while read -r line; do
        [[ ! "$line" =~ ^(s|v)d ]] && continue
        local col1="$(printf "$line" | awk '{print $1}')"
        local col2="$(printf "$line" | awk '{print $2}')"
        local col3="$(printf "$line" | awk '{print $3}')"
        local col4="$(printf "$line" | awk '{print $4}')"
        [[ "$col2" == "0.00" ]] && continue

        local rust="$(cat /sys/block/$col1/queue/rotational)"
        [[ $rust == 0 ]] && local is_rust="SSD" || local is_rust="spinning disk"

        printf "\r~ /dev/$col1 seeing ${col3}MiB w/sec and ${col4}MiB r/sec in $col2 IOPS on ${is_rust}\n"
    done <<< "$( iostat -d -m | sed '/^$/d' | tail -n+3 | awk '{print $1,$2,$3,$4}' )"

print_iostat outputs something like:

~ /dev/sda seeing 0.13MiB w/sec and 0.01MiB r/sec in 7.20 IOPS on spinning disk

Starting with the last line we run iostat and trim it down to just the data we are interested in; using sed to purge the empty lines, tail to remove the top three lines of headers and awk to return specific columns.

Now we can iterate over these lines, each line covering a different drive. We drop anything which doesn’t match the ^(s|v)d pattern, this limits our inputs to just physical drives, excluding things like systemd user slices.

After assigning each column to variable for brevity later, we then check if the IOPS is zero and skip that record.

We find out whether the disk being reported on is a rotating mechanical disk or a solid state drive with /sys/block/sda/queue/rotational, giving 1=rotational and 0=ssd.

Everything below is in the function print_motd

# Trap Ctrl-C to kill motd
trap return INT

It’s important to be able abort .motd's execution, namely with ^C. By trapping the Interrupt signal we can trigger a function return instead of the usual ^C behaviour being caught by bash and ending the session before it’s begun.

local uptime="$( uptime | tr -s ' ' | awk -F, '{ print $1 }' | cut -d\  -f4- )"
local uptime="$( printf "${uptime}" | awk -F\: '{print $1, "hours", $2, "minutes"}' )"
printf "\r~ $(hostname -s) up for ${uptime}\n"

local loadavg="$( uptime | sed 's/^.*age: //' )"
printf "\r~ System load is ${loadavg}\n"

Humanify uptime's output into hostname up for x hours y minutes and System load is 0.06, 0.08, 0.08.

if [ "$bashrc_end" -gt 1 ]; then

I’ve configured print_iostat to only print when bash takes more than a second to load, as I know my bashrc takes much less than a second to execute; the most likely reason for slow start-up is the system disk is busy, which is good to know upon logging in.

usrcount="$( /usr/bin/w | tail -n+3 | awk '{print $1}' | uniq | wc -l )"
printf "\r~ Logged in as $USER - "
if [[ "${usrcount}" == "1" ]]; then
    printf "You're the only one here!"
    printf "${usrcount} users online."

This section humanifies w's output, as-well as indicating which user you logged in as. The usrcount variable stores the count of a deduplcated list of users which is printed if the count is greater than one, otherwise it states how lonely the box feels.

recent_usr=$(last | head -n-2 | grep "$(date '+%a %b %d')" | egrep -v "$USER|reboot|still logged in" | awk '{print $1}' | sort | uniq | wc -l)
past_usr=$(expr $recent_usr - $usrcount | tr -d '-')
if [[ "$past_usr" -gt 1 ]]; then
    [[ "${usrcount}" == "1" ]] && printf " but" || printf " with"
    printf " $past_usr have been on today.\n"
    printf "\n"

Here I count the users who have logged in today; this indicator could be useful when investigating boxes which shouldn’t typically have any logins for example. It seems on popular boxes /var/log/last takes long enough to read that it’s noticable.

This was a nice idea which ended up being too heavy to leave in by default, but I like to keep it around. I could start loading this file further up the script and throw it into the background, ready to be read at this stage - but I haven’t done this.

usrps=$(ps aux | tail -n+2)
while read -r line; do
    printf '$line\n' | awk '$8 ~ /Z/ {print $1 " has zombie " $2}'
done <<< "$usrps"

Another questionably useful section, reading ps aux line by line to find Zombie processes, these can tie up a box’s resources, cause other processes to fail and eventually cause a crash. So it’s important to know if one exists - I haven’t had a chance to test this and I suspect it will fail because ps aux will hang once it encounters the zombie process… #FIXME

if [[ "$bashrc_end" ]] && [[ "$bashrc_end" -gt 1 ]]; then
    printf "\r~ bash started in ${bashrc_end} second"
    case "${bashrc_end}" in
        "1") printf "!\n";;
        *) printf "s!\n";;

Lastly I want to know if bashrc started slowly, this variable is already used by print_iostat but I like to have a specific message too. I use a simple case to make make “second” plural based on the number of seconds.