Did you know that you can get your macOS Terminal to display more than just your Last Login time when you open a new session?
It’s called a MOTD (Message of the Day) and is common in many computer systems. I wanted to learn how I could make one for my Terminal.
My inspiration was Oh My Zsh’s installation success message:
Here’s how I learned how to replicate it.
Step 1: Create motd.sh
In Terminal, make sure you’re in your home directory (Users > your-username). You can use the command cd
to quickly get there.
Then use the command touch motd.sh
to create the file.
Then use the command nano motd.sh
to edit the file.
We can start with something simple like echo "Hello World!"
.
Then press Ctrl + O to Save (or “WriteOut”), then press Enter to confirm the file name, then press Ctrl + X to exit.
Note: As the motd.sh file gets bigger and more complicated, you may find it easier to work on it in TextEdit or Visual Studio Code instead of Terminal’s nano editor.
Make it executable
For us to be able to run the motd.sh file later, it must be executable. Enter the following command to make it executable for all users:
chmod a+x motd.sh
chmod
is the command used for permission settings for files & folders.a+x
is to add the execute permission (“x”) to a file for all users (“a”).
OPTIONAL: After running the chmod
command, you can then use the ls -alh
command to view the permission settings for your files and see if the permission was successfully updated for motd.sh. Read this Intro to Shell Scripting using Zsh for more details.
Step 2: Update .zprofile
In your home directory (Users > your-username), you should have a hidden file called .zprofile
.
- If you’re using Finder, you can show hidden files by pressing:
Command + Shift + Period (.) - If you’re using Terminal, you can show hidden files by adding
-a
after thels
command (sols -a
).
Using your preferred text editor, add the following to the .zprofile
file:
# Display Message of the Day (MOTD)
./motd.sh
This is how your .zprofile
should look like now:
And this is how your Terminal should look like after opening a new session:
Step 3: Update motd.sh
Now that we have a working proof of concept, we can get creative with the motd.sh file. I mostly reverse-engineered the code from Oh My Zsh and broke it down into more easily digestible chunks as shown in the examples below.
Add Shebang
Before we jump into the examples… One important thing we missed in our motd.sh file earlier is a “shebang.” It starts with #!
and needs to be located on the 1st line of the file. The purpose of a shebang is to specify the correct shell to use for a shell script.
Until 2019, the relevant shebang for scripts intended for macOS’ Terminal would have been #!/bin/bash
. But then Apple switched from Bash to Zsh.
For Zzsh, I could find 3 potential shebang options:
#!/bin/zsh
#!/usr/bin/zsh
#!/usr/bin/env zsh
(use this one)
The 3rd variation is used by Oh My Zsh, and is also recommended in the MacPowerUsers forum, so that’s the one we’ll use as well.
To learn more about shebangs, check out: https://scriptingosx.com/2017/10/on-the-shebang/.
Example 1: Vertical Color Variation
In the first example, the goal is to get familiar using color and working with variables.
#!/usr/bin/env zsh
RED=$(printf '\033[38;5;196m')
ORANGE=$(printf '\033[38;5;202m')
YELLOW=$(printf '\033[38;5;226m')
GREEN=$(printf '\033[38;5;082m')
TEAL=$(printf '\033[1;36m')
BLUE=$(printf '\033[38;5;021m')
PURPLE=$(printf '\033[38;5;093m')
PINK=$(printf '\033[38;5;163m')
RESET=$(printf '\033[0m')
printf "\n"
printf "%s Hello World %s\n" "$RED" "$RESET"
printf "%s Hello World %s\n" "$ORANGE" "$RESET"
printf "%s Hello World %s\n" "$YELLOW" "$RESET"
printf "%s Hello World %s\n" "$GREEN" "$RESET"
printf "%s Hello World %s\n" "$BLUE" "$RESET"
printf "%s Hello World %s\n" "$PURPLE" "$RESET"
printf "%s Hello World %s\n" "$PINK" "$RESET"
printf "\n"
Inside of printf
, you’ll notice two %s
in each line. These are placeholders for strings. The values for these strings are specified at the end of the printf
statement. In our case, we use them to specify different color commands.
The $RESET
color variable refers to the default color set in Terminal (usually white). This script would work perfectly fine without a color reset after every line, but it’s good practice to have it to avoid the color from the last line bleeding into the rest of Terminal.
Example 2: ASCII Art & HereDoc
ASCII art takes advantage of all the special characters we rarely use on our keyboards to create large letters or anything else you can imagine such as animals, faces, logos, skylines, and so on.
People used to have to create ASCII art manually by hand; luckily now we have ASCII art generators that can do all the tedious work for us in seconds. Here’s a sample of just some of the many different ways that “hello word” can be generated:
The issue with ASCII art is that some of the symbols — such as the backtick (`), backslash (\), and single quote (‘)— can be mistaken for “escape characters” in shell scripts. This can cause commands like printf
to end prematurely and mess up subsequent commands. The solution for this is to use a HereDoc and the cat
command. The reason cat
is useful is because it shows the literal contents of what is fed into it. In other words, “escape characters” have no power inside of cat
.
#!/usr/bin/env zsh
RED=$(printf '\033[38;5;196m')
ORANGE=$(printf '\033[38;5;202m')
YELLOW=$(printf '\033[38;5;226m')
GREEN=$(printf '\033[38;5;082m')
TEAL=$(printf '\033[1;36m')
BLUE=$(printf '\033[38;5;021m')
PURPLE=$(printf '\033[38;5;093m')
PINK=$(printf '\033[38;5;163m')
RESET=$(printf '\033[0m')
LINE_1=$(cat << 'EOF'
_ _ _ _ _
EOF
)
LINE_2=$(cat << 'EOF'
| | | | | | | | |
EOF
)
LINE_3=$(cat << 'EOF'
| |__ ___| | | ___ __ _____ _ __| | __| |
EOF
)
LINE_4=$(cat << 'EOF'
| '_ \ / _ \ | |/ _ \ \ \ /\ / / _ \| '__| |/ _` |
EOF
)
LINE_5=$(cat << 'EOF'
| | | | __/ | | (_) | \ V V / (_) | | | | (_| |
EOF
)
LINE_6=$(cat << 'EOF'
|_| |_|\___|_|_|\___/ \_/\_/ \___/|_| |_|\__,_|
EOF
)
printf "\n"
printf "%s%s%s\n" "$PURPLE" "$LINE_1" "$RESET"
printf "%s%s%s\n" "$BLUE" "$LINE_2" "$RESET"
printf "%s%s%s\n" "$GREEN" "$LINE_3" "$RESET"
printf "%s%s%s\n" "$YELLOW" "$LINE_4" "$RESET"
printf "%s%s%s\n" "$ORANGE" "$LINE_5" "$RESET"
printf "%s%s%s\n" "$RED" "$LINE_6" "$RESET"
printf "\n"
For Example 2, I generated “hello world” using the “Big” or “Doom” font in Patorjk’s ASCII generator.
- If you want to print the ASCII Art in a single color, you can use a single HereDoc.
- If you want each line to be a different color, you’ll need to split up the ASCII art into 6 separate lines which you’ll then print separately (as shown above).
Example 3: Horizontal Color Variation
Changing color within the same line is as simple as adding an %s
before the letter you want to color, and then adding a color variable to the end of the printf
statement for each %s
used.
We can also bundle all the color variables into an array. Just make sure that the number of colors within the array matches the number of %s
's used in the printf
statement. In our example below, that number is 9.
#!/usr/bin/env zsh
RED=$(printf '\033[38;5;196m')
ORANGE=$(printf '\033[38;5;202m')
YELLOW=$(printf '\033[38;5;226m')
GREEN=$(printf '\033[38;5;082m')
TEAL=$(printf '\033[1;36m')
BLUE=$(printf '\033[38;5;021m')
PURPLE=$(printf '\033[38;5;093m')
PINK=$(printf '\033[38;5;163m')
WHITE=$(printf '\033[1;37m')
RESET=$(printf '\033[0m')
RAINBOW=(
"$RED"
"$ORANGE"
"$YELLOW"
"$GREEN"
"$TEAL"
"$BLUE"
"$PURPLE"
"$PINK"
"$RED"
)
printf "\n"
printf "%sH %sE %sL L %sO %sW %sO %sR %sL %sD" $RAINBOW
printf "\n"
Example 4: Horizontal Color Variation with ASCII Art
To horizontally color ASCII art, the concept is the same as in example #3 — it’s just much messier to execute. You’ll need a lot of concentration when placing %s
, and the ASCII art may appear to get a bit disfigured as you do this. But stay focused and trust the process.
#!/usr/bin/env zsh
RED=$(printf '\033[38;5;196m')
ORANGE=$(printf '\033[38;5;202m')
YELLOW=$(printf '\033[38;5;226m')
GREEN=$(printf '\033[38;5;082m')
TEAL=$(printf '\033[1;36m')
BLUE=$(printf '\033[38;5;021m')
PURPLE=$(printf '\033[38;5;093m')
PINK=$(printf '\033[38;5;163m')
WHITE=$(printf '\033[1;37m')
RESET=$(printf '\033[0m')
RAINBOW=(
"$RED"
"$ORANGE"
"$YELLOW"
"$GREEN"
"$TEAL"
"$BLUE"
"$PURPLE"
"$PINK"
"$RED"
)
printf '\n'
printf " %s _ %s %s _ _ %s %s %s %s %s _ %s _ %s\n" $RAINBOW $RESET
printf " %s | |__ %s ___%s| | |%s ___ %s__ __%s___ %s_ __%s| |%s __| | %s\n" $RAINBOW $RESET
printf " %s | '_ \ %s/ _ \ %s| |%s/ _ \ %s\ \ /\ / / %s_ \%s| '__%s| |%s/ _\` | %s\n" $RAINBOW $RESET
printf " %s | | | |%s __/%s | %s| (_) | %s \ V V / %s(_) %s| | %s| |%s (_| | %s\n" $RAINBOW $RESET
printf " %s |_| |_|%s\___%s|_|_|%s\___/ %s \_/\_/ %s\___/%s|_| %s|_|%s\__,_| %s\n" $RAINBOW $RESET
printf '\n'
Note: I managed to print this ASCII Art without using HereDoc or cat
. I noticed that only the single backtick (`) on the “d” in the 3rd line was causing printf
to escape early, and so I neutralized that backtick with a backslash.
Example 5
No new concepts in this example, it’s just a slanted version of Example 4. It is the most similar to the original “Oh My Zsh” ASCII Art which inspired this sidequest of mine.
#!/usr/bin/env zsh
RED=$(printf '\033[38;5;196m')
ORANGE=$(printf '\033[38;5;202m')
YELLOW=$(printf '\033[38;5;226m')
GREEN=$(printf '\033[38;5;082m')
TEAL=$(printf '\033[1;36m')
BLUE=$(printf '\033[38;5;021m')
PURPLE=$(printf '\033[38;5;093m')
PINK=$(printf '\033[38;5;163m')
WHITE=$(printf '\033[1;37m')
RESET=$(printf '\033[0m')
RAINBOW=(
"$RED"
"$ORANGE"
"$YELLOW"
"$GREEN"
"$TEAL"
"$BLUE"
"$PURPLE"
"$PINK"
"$RED"
)
printf '\n'
printf ' %s __ %s %s __ __ %s %s %s %s %s__ %s __ %s\n' $RAINBOW $RESET
printf ' %s / /_ %s___ %s/ // / %s___ %s_ __%s ____ %s_____ %s/ /%s ___/ / %s\n' $RAINBOW $RESET
printf ' %s / __ \ %s/ _ \ %s/ // /%s/ __ \ %s| | /| / /%s/ __ \ %s/ ___/%s/ /%s/ __ / %s\n' $RAINBOW $RESET
printf ' %s / / / /%s/ __/%s/ // /%s/ /_/ / %s| |/ |/ /%s/ /_/ /%s/ / %s/ /%s/ /_/ / %s\n' $RAINBOW $RESET
printf ' %s/_/ /_/ %s\___/%s/_//_/ %s\____/ %s|__/|__/%s \____/%s/_/ %s/_/%s \__,_/ %s\n' $RAINBOW $RESET
printf '\n'
# Note: you need "%s" X8 times per line
Last Login
I wanted to also change the style and formatting of the “Last Login” message at the top of my Terminal, but I couldn’t find anyway to do so. If you have the answer, please comment down below.
I did learn that creating a file called .hushlogin
in your home directory will cause the default “Last Login” message to not appear at all. I’m guessing I’ll have to do that and then re-create the last login information in my motd.sh file.
Other Examples / Inspiration
Here are some more advanced MOTDs that others have created and that I hope to learn from one day when I have more time. They are harder to make because they involve pulling data from various places instead of just displaying the same static content.
Conclusion
I hope this guide was helpful. You should now have all the foundations needed to get creative with your own static MOTD designs. 🧑🎨🎨
Feel free to ask questions in the comments, and please share any other nice MOTD examples that you’ve seen. 😊