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:
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:
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.