Ubuntu – Appending code/text in previous console output to display status

bashcommand linescriptsservices

I have been unable to find out how this "code" below is created.

# sudo /etc/init.d/samba restart
[ ok ] Restarting nmbd (via systemctl): nmbd.service.
[ ok ] Restarting smbd (via systemctl): smbd.service.

Specifically after calling the command, this is shown at first:

[ .. ] Restarting nmbd (via systemctl): nmbd.service.

Followed by a comfirmation of restart by the service, it changes to

[ ok ] Restarting nmbd (via systemctl): nmbd.service.

with the .. changing to ok

I would like to incorporate these into my own scripts but haven't been able to find the code for these or any similar.

Help would be appreciated!

Please note, I am only using Samba as an example since this presents the output I am referring too.

The only possibility, to my knowledge, is that it runs some for of python script, but going through the service file for any arbitary service that has a similar output has no mention of a python script nor something that echo's ok

cat /etc/init.d/samba

#!/bin/sh

### BEGIN INIT INFO
# Provides:          samba
# Required-Start:
# Required-Stop:
# Default-Start:
# Default-Stop:
# Short-Description: ensure Samba daemons are started (nmbd, smbd and samba)
# Description: Starts Samba, a Windows AD and SMB/CIFS fileserver for UNIX
### END INIT INFO

set -e

# start nmbd, smbd and samba-ad-dc unconditionally
# the init scripts themselves check if they are needed or not
case $1 in
    start)
        /etc/init.d/nmbd start
        /etc/init.d/smbd start
        /etc/init.d/samba-ad-dc start
        ;;
    stop)
        /etc/init.d/samba-ad-dc stop
        /etc/init.d/smbd stop
        /etc/init.d/nmbd stop
        ;;
    reload)
        /etc/init.d/smbd reload
        ;;
    restart|force-reload)
        /etc/init.d/nmbd "$1"
        /etc/init.d/smbd "$1"
        /etc/init.d/samba-ad-dc "$1"
        ;;
    status)
        status=0
        NMBD_DISABLED=`testparm -s --parameter-name='disable netbios' 2>/dev/null || true`
        SERVER_ROLE=`samba-tool testparm --parameter-name="server role"  2>/dev/null | tail -1 || true`
        if [ "$SERVER_ROLE" != "active directory domain controller" ]; then
            if [ "$NMBD_DISABLED" != "Yes" ]; then
                /etc/init.d/nmbd status || status=$?
            fi
            /etc/init.d/smbd status || status=$?
        else
            /etc/init.d/samba-ad-dc status || status=$?
        fi
        exit $status
        ;;
    *)
        echo "Usage: /etc/init.d/samba {start|stop|reload|restart|force-reload|status}"
        exit 1
        ;;
esac

Best Answer

printf and overwriting with carriage return

This type of "magic" can be done via printf and carriage return "\r" to overwrite existing output. However, you will have to be conscious for consecutive lines. Observe this example:

#!/bin/bash

string="[  ] pinging google.com "

printf "%s" "$string"

if ping -c 4 -q google.com > /dev/null 
then
    printf "\r[OK"
    printf "\n\n"
fi

Notice how we have the "status" string print first, then we use carriage return to jump back to the beginning and overwrite first 3 characters with "[OK" string. The following two newlines is just example of what you'd want to do to move the script onwards and print more lines. As for the if command ; then . . . fi , this is simple structure which executes body of if statement conditionally , depending on command output.

Disadvantage of this approach is that if you don't match the character lengths of what you're printing, then it might show through.

$ printf "Hello\rcat\n" 
catlo

Slightly better approach: clearing the line with escape code

We can take advantage of ANSI escape code for clearing line (in this case, in octal \033[2K ) for getting rid of what we previously had on the line. This has advantage of not running out in the issue of matching/not-matching length of what you print when you reset the cursor back to the beginning.

Here's an example, with added UTF-8 characters for check and cross-mark

#!/bin/bash

string="[ ] pinging google.com "
printf "%s" "$string"

if ping -c 4 -q google.com > /dev/null 
then
    # clear previous line, add UTF checkmar to string
    printf "\r%b" "\033[2K"
    string="[\U2713] pinging google.com "
else
    # clear previous line, add UTF checkmar to string
    printf "\r%b" "\033[2K"
    string="[\U274C] pinging google.com "
fi
printf "%b" "$string"
Related Question