Random Terminal Message of the Day

Dan Moren posted a Terminal Message of the Day tip on Six Colors a few days ago, and I decided I would configure my Mac with a MOTD as well. However, I want a random one from a list every time I open a terminal rather than seeing the same one over and over.

The easiest way to do this is to avoid the /etc/motd file altogether and use a script to read a random line out of a text file and display that when you open a terminal window. There are three parts to this, two of which take all the work: a text file full of messages of the day, a script to randomly grab one, and a means by which to execute it automatically when you open terminal.

Find a place on your Mac you want to store scripts, if you don’t already have one. Making a folder called Scripts in your Home folder works well.

Make a Scripts folder in your Home folder

Inside the Scripts folder, make a text file with your messages of the day inside. I have one with a bunch of English-translation Ghost in the Shell quotes in it.

All things change in a dynamic environment. Your effort to remain what you are is what limits you.
Build your future, follow your ghost.
If you merely live within the dreams of other people it's no different from being dead.
We weep for the blood of a bird, but not for the blood of a fish. Blessed are those with a voice. If the dolls could speak, no doubt they'd scream, 'I didn't want to become human.
The human body is a machine which winds its own springs. It is the living image of perpetual motion.
If our Gods and our hopes are nothing but scientific phenomena, then let us admit it must be said that our love is scientific as well.
Don't send a rabbit to kill a fox.
Overspecialize and you breed in weakness. It's slow death.
No matter how far an ass travels, it won't come back a horse.
The net is vast and infinite.

The quotes are each on their own line (separated by a carriage return).

Now you need a scripting language. I started messing with Ruby, with which I am very unfamiliar but thought it would be fun to mess with, but I switched to Python as soon as I encountered Ruby’s EOF error and decided I didn’t want to pursue the specifics of Ruby file handling at the moment.

A quick search for a Python script to read random lines from a file took me to a w3resource article titled Python File I/O: Read a random line from a file.

Here’s their script:

import random
def random_line(fname):
    lines = open(fname).read().splitlines()
    return random.choice(lines)
print(random_line('test.txt'))

I pretty much used it verbatim. All I did was change the name of the file to read and add a blank line above and below the message of the day output.

import random
def random_line(fname):
    lines = open(fname).read().splitlines()
    return random.choice(lines)
print("\n" +  random_line('/Users/Scott/Scripts/motd.txt') +  "\n")

The reason I specified the absolute file path is because the script and motd.txt reside in a different directory than the thing that calls the script when I open a terminal window. Obviously you’d have change that path with whatever your username is on your Mac.

Anyway, save that script to a file that ends in .py, like random_motd.py. Save it in the same directory as the file containing your messages of the day for simplicity sake. The set its file permissions to 755, so it’s executable.

Incorrect file permissions (744):

drwxr-xr-x   5 scott  staff   160 Mar 30 13:28 .
drwxr-xr-x+ 29 scott  staff   928 Mar 30 13:28 ..
-rw-r--r--   1 scott  staff   879 Mar 30 10:39 motd.txt
-rwxr--r--   1 scott  staff   182 Mar 30 13:28 random_motd.py

Execute the following command in terminal to set the permissions to 755.

chmod 755 random_motd.py

Correct file permissions:

drwxr-xr-x   5 scott  staff   160 Mar 30 13:28 .
drwxr-xr-x+ 29 scott  staff   928 Mar 30 13:28 ..
-rw-r--r--   1 scott  staff   879 Mar 30 10:39 motd.txt
-rwxr-xr-x   1 scott  staff   182 Mar 30 13:28 random_motd.py

Now the file permissions on random_motd.py indicate that owner can read, write, and execute the file, and group and everyone can read and execute the file.

You can now test the script simply by running it in Python.

scott@Dragonfly Scripts % python random_motd.py 

No matter how far an ass travels, it won't come back a horse.

scott@Dragonfly Scripts % 

The last piece of the puzzle is getting the Python script to execute whenever you open a new terminal window. How you do this depends on which shell you’re using. OS X and macOS have historically used bash as the default shell, but new user accounts created in Catalina or later will use zsh. If you migrated your user accounts to Catalina, you probably have bash; if you did a clean install of Catalina including a fresh user account, you probably have zsh.

Unix shells have different user profile related files that are used to set user-specific configurations and launch things on login. In the case of macOS, the .bash_profile is used, and for zsh, .zshrc instead. These files are invisible files located in your home directory. You can see them if you execute the following commands in terminal:

scott@Dragonfly ~ % cd ~
scott@Dragonfly ~ % ls -ld .?*

The first command (cd ~) is unix shorthand for changing directory to your home directory. The second command (ls -ld .?*) is a list command that creates a long listing (shows permissions and owners), shows directory names instead of contents, and then shows any files that have at least one period at the beginning of the file name.

Unix uses the . character at the start of file names to make them hidden in normal list views (and in the Finder, in the case of macOS).

Here’s what the ls -ld .?* command shows me in my case:

-r--------   1 scott  staff      7 Oct  8 21:10 .CFUserTextEncoding
-rw-r--r--@  1 scott  staff  14340 Mar 30 13:31 .DS_Store
drwx------   2 scott  staff     64 Mar 30 13:58 .Trash
-rw-------   1 scott  staff     96 Oct  9 19:02 ._PrintopiaImport
drwxr-xr-x  16 scott  staff    512 Mar 28 11:15 .atom
-rw-------   1 scott  staff    284 Oct 22 19:24 .bash_history
-rw-r--r--   1 scott  staff     35 Oct 13 15:55 .bash_profile
drwx------  18 scott  staff    576 Oct 22 19:24 .bash_sessions
drwx------   3 scott  staff     96 Oct  8 21:11 .cups
-rw-r--r--   1 scott  staff    222 Jan  6 10:05 .gitconfig
-rw-------   1 scott  staff     43 Mar 30 11:20 .lesshst
drwx------  21 scott  staff    672 Mar  5 12:27 .ssh
-rw-------   1 scott  staff   9848 Mar 30 13:28 .viminfo
drwxr-xr-x   4 scott  staff    128 Dec 13 19:31 .vscode
-rw-------   1 scott  staff  16944 Mar 30 13:28 .zsh_history
-rw-r--r--   1 scott  staff    185 Mar 30 11:23 .zshrc

And although I do have a .bash_profile there, it’s a holdover from before I converted to zsh as my shell. I need to add the command to execute my Python script to my .zshrc file since I am using zsh now.

All you have to do is add the following line to whichever of these applies to you (.bash_profile or .zshrc):

python ~/Scripts/random_motd.py

That assumes that you named your Python script random_motd.py and placed in a folder called Scripts in your Home folder.

In my case, here’s my current, very simple .zshrc file, as seen using more:

scott@Dragonfly ~ % more .zshrc 
alias ll="ls -la"
alias llrt="ls -latr"
alias lltr="ls -latr"
if type brew &>/dev/null; then
  FPATH=$(brew --prefix)/share/zsh/site-functions:$FPATH
fi
python ~/Scripts/random_motd.py

Now that you’ve updated your .bash_profile or .zshrc appropriately, you can either open a new terminal window to see your message of the day in action, or you can just source the newly edited file for the changes to take effect in your current terminal window:

scott@Dragonfly ~ % source .zshrc

The human body is a machine which winds its own springs. It is the living image of perpetual motion.

scott@Dragonfly ~ % 

You’d type source .bash_profile instead of source .zshrc if you’re using bash as your shell instead of zsh.

That’s it. Very simple, but it touches on a few different aspects of simple scripting on the Mac, using the Mac terminal, and Unix conventions in general.