DEV Community

Cover image for Weird Color Stuff In The Terminal
Bill C
Bill C

Posted on

Weird Color Stuff In The Terminal

I recently got a new mac mini (not the latest and greatest, but plenty for my needs) and my intention is to use it for dev. Something I like to do is setup the terminal so that when I start a new session I get a little quote from Oblique Strategies.

There's lots of implementations for this existing in the wild, from the very old unix command fortune, to sundry web apps, to stuff written in modern languages. But, I wanted to diy the solution.

I had just gone through a fun tutorial for setting up oh-my-zsh with a nice color scheme from iterm2colorschemes.com and a decent prompt and I was wondering: can I make my oblique strategy look nice? how can you actually use the colors from your scheme in the output in your cli?

Terminal Color Basics.

The first clue for how to make your cli text output more colorful comes from the image defining the color scheme that you get from iterm2colorschemes.com. Here's the one for the scheme Peppermint.

Peppermint iterm2 color scheme

Something you might notice is that there are things like 4dm along the top, and like (1;)?3dm off to the left of the table. And that's what this image is, its a table of all the possible text and background color pairs and how they look. But how do you use them?

The answer is an escape sequence. Try something like

echo '\e[1;35;47m walrus'
Enter fullscreen mode Exit fullscreen mode

in your terminal. You should have the word 'walrus' with a preceeding space written in some fancy colors. Play around with different digits where the 5 and 7 are. Delete or include the 1;. Neat!

Of course, the colors will be from your color scheme, either the default, or from whatever scheme you've installed (that tutorial I linked above is super clear about how to do this).

If you're like me and you take your code looking like line noise as a code smell, you might want to try something a little more readable.

tput setaf 13; tput setab 7; echo ' walrus'
Enter fullscreen mode Exit fullscreen mode

That should look the same as what you got from my earlier echo command. ; runs the command but doesn't append a new line to the output. setaf is 'set as foreground' and setab is 'set as background'. The 13 is 8+5: the 5 selects the base color, adding 8 brightens it (like using 1; did in the escape sequence). Like the table shows, there's 18 permissible foregrounds, and 10 permissible backgrounds. I'll let you work out how to get them all.

Strange state

So, I learnt this after some googling and stack overflow and looking at man pages for tput and terminfo and was feeling pretty good, but I wanted the background color to stretch to the end of the line, and for there to be colored lines above and below my one line quote. I reasoned some newlines would do the trick and ended up with something like

tput setaf 11; tput setab 4; echo "\n\n\t"walrus"\n"
Enter fullscreen mode Exit fullscreen mode

and it worked! So I put it at the top of my .zshrc (because other stuff complained if I put it at the bottom) and when I source .zshrc'd it worked! And when I opened a new tab it didn't work!

What the hell? I went backwards and forwards with it a few times, and had a tab where sourcing the file worked, with the background color extending all the way to the ends of my empty lines and the line with text, and another where the color only covered the tab and the word 'walrus'.

This felt pretty crazy at the time. Somehow, the other stuff I was doing in the terminal, like editing files and resizing windows, was occasionally creating persistent state that was telling the terminal to use the background on the full line. And I wasn't alone in seeing this weird behaviour.

The accepted answer at that link talking about using an escape sequence to clear to end of line was good. I just defined \x1B[K as a variable and liberally sprinkled it in my output, and was finally seeing what I wanted. But I didn't like using tput for some escapes and the raw sequence for others. tput el was my friend (found on the man page for
terminfo after searching for the word 'clear').

Getting a random line from a file

Long story short on this one, the code ended up looking like

CLREOL=$(tput el)

oblique_line_no=$(( RANDOM%$(wc -l oblique.txt | awk '{print $1}') + 1 ))
oblique_line=$(sed -n ${oblique_line_no}p oblique.txt)

tput bold; tput setaf 11; tput setab 4; echo "\n${CLREOL}\n${CLREOL}\t"$oblique_line"${CLREOL}\n${CLREOL}"
echo
Enter fullscreen mode Exit fullscreen mode

To decompose that a bit:

  • RANDOM makes a random number
  • $((...)) evaluates arithmetic, with % doing mod
  • wc will count lines of a file, but you need to trim the output a bit (the pipe into awk)
  • sed has a one liner to print just one line of a file.

Takeaways

Firstly, if you're going to dev, you'll spend some time on your command line, maybe even a lot. Make it something you like. I really love the off kilter suggestions from oblique strategies, you might love some ascii art, or a really stripped down experience. Whatever you want, make the terminal your own.

Secondly, test your code. I would never have seen that weird behaviour if I wasn't testing my code to see what it would do in a variety of circumstances, or rather, I would have stepped away thinking the problem solved, only for it to rear its head when I next opened a terminal.

Finally, don't give up! If there's an effect you want to achieve, the tools are almost certainly out there waiting for you to learn about them.

PS touch .hushlogin to remove the 'last login' stuff from your osx terminal. Concise articles are great!

Top comments (0)