Run lolcat after each command?

Solution 1:

UPDATE

I put my implementation here with install instructions:

https://github.com/dosentmatter/rainbow-bash-prompt

It uses the C implementation of lolcat but I modified it a little to make it psuedo-random.

OLD ANSWER

Here is how I did it. Add this to your .bashrc:

PS1_colorless=${PS1:-'\h:\W \u\$ '}

ESC=$(echo -e '\033')
SOH=$(echo -e '\001')
STX=$(echo -e '\002')
PS1_color_wrap='s/'$ESC'\\[[[:digit:];]*m/'$SOH'&'$STX'/g'

PS1="\$(lolcat -f <<< \"$PS1_colorless\" | sed '$PS1_color_wrap')"

It works by running lolcat dynamically on $PS1_colorless and doing a sed to add in control characters so line wrapping works correctly.

It takes a little less than 200 milliseconds to run. So it might be too slow for you. Here is an example I timed:

ruby lolcat time

I chose to use PS1 and not PROMPT_COMMAND because I wanted to be able to use the bash prompt escape sequences such as \h, \W, etc. which wouldn't be possible with PROMPT_COMMAND since I need to pass it to PS1 for expansion before running lolcat. You can use alternatives like ${HOSTNAME%%.*} to imitate the behavior of \h but I don't think you can do it for something like

\#     the command number of this command

It uses -f to force lolcat to run even though the output is being piped to sed. lolcat defaults to not output anything if the output is not to a tty.

After doing the lolcat, it does a sed to surround the ansi color syntax such as ESC[38;5;184m (ESC is the control character \033) with the control characters SOH and STX so it becomes SOHESC[38;5;184mSTX. SOH and STX are just \[ and \] respectively in the bash prompt control characters. I have to use SOH and STX control characters instead of \[ and \] because I am generating colors dynamically. \[ and \] would not work because they are translated to control characters when PS1 is first parsed. \[ and \] would work if you used PROMPT_COMMAND to generate output for PS1 but then I wouldn't be able to use \u and \W because lolcat would have been run before passing \u to PS1 for expansion.

For reference: https://stackoverflow.com/questions/24839271/bash-ps1-line-wrap-issue-with-non-printing-characters-from-an-external-command

Characters surrounded by SOH and STX are treated as non printing characters. This is required so line-wrapping works correctly and doesn't treat the ansi color as actual visible characters.

If you want to use literal non-printable control characters, you can replace

this

ESC=$(echo -e '\033')
SOH=$(echo -e '\001')
STX=$(echo -e '\002')
PS1_color_wrap='s/'$ESC'\\[[[:digit:];]*m/'$SOH'&'$STX'/g'

with this

PS1_color_wrap='s/^[\\[[[:digit:];]*m/^A&^B/g'

Note the ^[, ^A, and ^B are the literal control characters so you can't just copy and paste. You would have to use something like vim to enter them

In vim:

^[ == Ctrl+vEsc or Ctrl+vo033

^A == Ctrl+vCtrl+a or Ctrl+vo001

^B == Ctrl+vCtrl+b or Ctrl+vo002

EDIT (a little faster in python): The python one seem to run a little bit faster:

python lolcat time

Change these variables in your .bash_profile:

PS1_colorless=${PS1:-'\h:\W \u\$'}
PS1_newline="tr -d '\n'"
PS1_spacing=' '
PS1="\$(lolcat -F 6 -p 25 -f <<< \"$PS1_colorless\" | $PS1_newline | sed '$PS1_color_wrap')"
PS1+=$PS1_spacing

The python version has extra newlines in the output so I remove them with the tr. It also removes trailing spaces so I removed the trailing spaces from PS1_colorless and add them back with PS1_spacing.

You can get it here: https://github.com/tehmaze/lolcat

I will update if I ever get the C port working: https://github.com/jaseg/lolcat

I can't get it to build on mac os. If anyone can get it working on linux or mac os, please let me know.

Solution 2:

Why exactly you would want to do this is beyond me, but there are two ways you can accomplish this:

1) you can put the command in the PS1 variable (the variable the controls your prompt)

or...

2) Use the variable PROMPT_COMMAND (preferred)

Modifying PS1

For example, your prompt might default to displaying the hostname and the username:

Allans-iMac:~ allan

To see the code, type echo $PS1 and we get:

\h:\W \u\$

Which equates to hostname, working directory, username and the dollar sign.

To run a command (using ls as an example) just add it in enclosed with backticks and assign it to PS1:

PS1=`ls`"\h:\W \u\$"

Now, every time a command is executed, successful or not, it will issue the ls command before displaying the prompt.

Using the PROMPT_COMMAND variable

Like above, but this time you set the variable PROMPT_COMMAND with the command you wish to execute. Again using ls as the example:

PROMPT_COMMAND=ls

Now, without having to modify the PS1(prompt) value, you can have a command execute every time.

You can set either of these values permanently in your .bash_profile located in the user's home directory.

Solution 3:

I made a shell extension for the world's fastest website generator that I make called Nift. It has an easter egg where you can turn on lolcat output for most things with lolcat.on (after starting the shell with eg. nift sh). You will even get rainbow output when pressing tab to get possible completion options, I doubt you get that with any other suggested solutions.

The shell extension is for f++ which is the in-built scripting language, which has these functions and these types available. But anything it doesn't recognise is run as a system call using the (probably primary/default) shell on your machine (hence calling it a shell extension in REPL shell mode).

Nift will look for a version of lolcat installed on your machine and otherwise use an in-built version of it which should be the world's fastest (it's near identical to my c++ implementation lolcat-cc which is the world's fastest). I highly recommend installing lolcat-cc (or another version of lolcat) on top of Nift though as otherwise you are frequently running the ~5mb Nift binary for basically all system calls, instead of a <1mb binary for lolcat.

f++ is somewhat of an interesting scripting language as well. Take this script for example which creates and deletes 100k empty text files. On my machine this runs in ~3.5 seconds whereas this Bash script doing essentially the same thing takes more like 3 minutes!! Some of the cool things you might already notice from that f++ script is you can expand variables inside strings, you can define variables with types, you can expand variables in to multiple parameters with function calls, you can have LOTS more than 10k input parameters for function calls (should be able to have millions!).

You can find some more information about the Nift REPLs (including shortcuts for different platforms) here.

If you need to define shell variables (not through f++ but the underlying shell) then you will need to do blocks of code using the sys/system function. You can also do blocks of code for Lua(JIT) and ExprTk similarly as they are both embedded in to Nift. You can use both Lua and ExprTk with accessing/modifying f++ variables as well..

So to get this shell (extension). Install Nift through a package manager or clone, make and install off GitHub. Enter nift sh in to your terminal to start the Nift f++ shell extension, then enter lolcat.on to turn on rainbow output.