Setting LS_COLORS colors of directory listings in bash terminal
This one I underestimated the importance of. But no more.
If you really use vim/perl/unix as I do- you are in bed with the command line. You're looking through a lot of file listings, regularly.
Using most guis, such as kde/gnome on ubuntu/fedora/suse/debian.. You'll notice when you do an ls on a directory- you most likely, by default, get some funny ephemera manifestations. What I mean is, directories may be listed in a different color. Maybe they are bold. And regular files are normal text. And some of them are in different colors!
What's up with that? Do we really give a shit if every jpg is red and every gif is blue, pdfs are purple and then notice also- JPG is not detected as a file ext to highlight and jpg *is*. Try it, change the ext of a JPG file to jpg, the color changes.
What is up with that? Well- I had been pleasantly ignoring that since- forever. I never cared to meddle or alter the settings, or even to look if there was a setting to affect that.
But recently I've been really curious to learn not just more code- more programming- but more of *how to work* more efficiently. I looked up how to affect these color and text formatted listings of directories- hoping that it may be helpful when looking through distros, through filesystems.. And you know what.. it is. Do you remember using vim and then one day actually taking the time to search and replace, properly, with capture.. And.. Wasn't it really fucking useful?
Ok, this one I know you're gonna roll your eyes at. And I did too, for years. But I would like you to take ten minutes of your life to give this a ride and see for yourself that it does help out a little. And the life of the code... These little things add up- using find xargs grep, using cv, perl one liners- and I'm gonna have to vouch for this one too. Directory listing text formatting.
- Ok, the thing you are looking to alter is a shell environment variable- on bash it's LS_COLOR.
- What is it set at currently? Run set and grep out for LS_COLOR:
$ set | grep LS_COLOR LS_COLORS='no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;35:*.cmd=00;32:*.exe=00;32:*.sh=00;32:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.t=93:*.pm=00;36:*.pod=00;96:*.conf=00;33:*.off=00;9:*.jpg=00;94:*.png=00;94:*.xcf=00;94:*.JPG=00;94:*.gif=00;94:*.pdf=00;91'
- Alright, wtf just happened. This string tells ls that when ls --color is called, these are the colors/text formatting to use.
Now, ls --color? When have you run that flag? This is set as an alias in some bashrc file somewhere. Likely not your ~/.bashrc. But in some /etc/$BASHRC?? file. If you want to find out in which exact place you're defaulting to use ls --color ...
$ find /etc/ 2>/dev/null | xargs grep -s 'alias ls' /etc/profile.d/colorls.sh: alias ls='ls --color=tty' 2>/dev/null /etc/profile.d/colorls.csh:alias ls 'ls --color=tty'Now, how the heck is this being called??? Look at your ~/.bashrc, it may have an entry to include /etc/bashrc if it exists, and then.. well.. there's some other default profile voodoo and such I'm not versed in.
How it works..
The string value of the LS_COLOR environment variable is parsed as a hash, internally. The stream of garble is understood as.. The delimiter is the color (:) symbol. The first part is what the element of the directory listing is, then assignment (=), and a style code. More than one style code can be assigned.
For the following chunk of string: di=00;1:fi=00:*.php=00;34, it means:
di(directory) =(assignment) 00(normal text) ;(and) 1(bold) :(delimiter, next entry..) fi(file) =(assignment) 00(normal text) :(delimiter, next entry..) *.php(everything matching *.php) =(assignment) 00(normal text) ;(and) 34(blue)
How to change it!
Knowing the codes:
Please do note.. that's a pretty lousy string to use. It's just an example. You need to play around with it and figure out what you really want. For that, you need to know what the codes are.. for the filesystem elements (no,li,di.fi.. etc), for setting up regexes (*.pm)- and what the codes mean (1 bold, 00 normal, 9 strikethrough). I picked up a good list from Bartman.
Here's that same list with some extras added- these work properly on GNU bash 3.0.
0 = default colour 1 = bold 4 = underlined 5 = flashing text 6 = no change 7 = reverse field 8 = black 9 = strikethrough (cool!) 10 - 29= no change 30 = light green 31 = red 32 = green 33 = orange 34 = blue 35 = purple 36 = cyan 37 = grey 38 = underline 39 = no change 40 = black background 41 = red background 42 = green background 43 = orange background 44 = blue background 45 = purple background 46 = cyan background 47 = grey background 90 = dark grey 91 = light red 92 = light green 93 = yellow 94 = light blue 95 = light purple 96 = turquoise 100 = dark grey background 101 = light red background 102 = light green background 103 = yellow background 104 = light blue background 105 = light purple background 106 = turquoise background
One way of managing colorschemes..
Yup. You can have colorschemes for dir listings. Crazy, huh?
All you would need to do is to save your colorschemes in files.
For example in ~/.ls_color-joe
If you want to import that via the current shell, just use the '.' operator, the command would be:
And now when you do a listing, it will use those colors. My god, though, why would you want to do that? What if you don't have the same ~/.bashrc in every system? You really want to copy and paste that string amongst various machines?
What could be convenient is to store them as files, and call them into your current shell with the dot operator. Or.. You can do this in your ~/.bashrc as..
if [ -f "~/.ls_color-joe"]; then . ~/.ls_color-joe; fi
- Making it easier to edit the color string
Now.. I hate to edit a string like that.. 'no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:ex=00;35'.. Yuck! So, what I've done for myself is my colorscheme file let's me enter things like:
# images *.jpg 35 *.gif 35 *.xcf 33 # code *.sh 91 *.pl 91
The file is still called the same way as explained above, it's just a bash file.. But.. it has a little magic. It allows human formatted LS_COLORS strings to automatically be turned into the proper bash environment variable string.
Or you could save the human readable format in a flat text file, for example ~/.mylscolors
# HUMAN_FORMATTED_DATA # list one per line # these are basic filesystem items no 00 # normal fi 00 # file di 00 34 # directory ln 00 36 # link pi 40 33 # pipe so 00 35 # bd 40 33 01 cd 40 33 01 or 01 05 37 41 mi 01 05 37 41 ex 00 91 # executable *.ai 00 91 # adobe ill *.doc 00 91 # msword shit # data, such as .db, .csv *.csv 95 *.dsv 95 *.db 95 *.sql 95 *.meta 95 # CONFS *.xml 95 *.yaml 95 *.yml 95 *.conf 95 # [a-z0-9]*rc # by now you should really know that everything after the # pound sign is a comment.. use vim, nice syntax highlighting
And then use this command to turn it into the LS_COLORS string:
$ cat ~/.mylscolors | grep '\w' | grep -v '^#' | sed 's/#.\+//' | perl -lane 'printf "%s=%s:", shift @F, join ";", @F;'
What if you wanted to save that output to your ~/.bashrc ? Yes, you could copy and paste the output into your ~/.bashrc. But that is not the unix way...
- Doing it via the command line instead of cutting and pasting..
What we do is redirect the output into the ~/.bashrc. First let's make sure we don't havbe a LS_COLORS string in there.. We can look inside via:
$ cat ~/.bashrc | grep LS_COLORS
If we do, let's just rip that right out..
$ perl -p -i -e 's/^export LS_COLORS=.*$//' ~/bashrc
Is perl too weird for you? We can use bash..
$ cp ~/.bashrc ~/.bashrc.bak; cat ~/.bashrc.bak | grep -v LS_COLORS > ~/.bashrc
The -v flag is match reverse, so no lines containing LS_COLORS will be spat out. Backing up the file is good, and also.. if you tried to to this to the file itself.. You're end up with a blank file:
# THIS IS WRONG and will delete your file: cat ~/.bashrc | grep -v LS_COLORS > ~/.bashrc
Ok, now we can turn the string into the variable, the source being human readable content.. and save it to the ~/.bashrc..
$ echo "export LS_COLORS='"$(cat ~/tmp/testlscolor | grep '\w' | grep -v '^#' | sed 's/#.\+//' | perl -lane 'printf "%s=%s:", shift @F, join ";", @F;')"' # source was ~/tmp/testlscolor" >> ~/.bashrc
Make sure you redirect the output as append '>>' and not overrite '>'.
Great. What if we wanted to make this into a command? So we can use the source, the human legible format of a LS_COLORS string anytime?
For that.. we need to more or less script all of our example...
- Making it all into commands
The first thing we should do here, is separate this into two commands, one should be a unix filter, and the other.. should be the procedure we want .
Now, a unix filter is the most important and useful kind of command you can write in unix. It simply takes standard input and spits to standard output. Read The Rule of Composition, it explains the idea behind filters.
- Making this a simple filter..
Will make it so the process can be used for anything else.
The cheap and simple way to do this, is do one of..
- a) Make it an alias in your ~/.bashrc
- This is a cheap and simple way to add commands to your environment. Aliases can be cool.
In your ~/.bashrc, enter this line:
alias string2lscolors="grep '\w' | grep -v '^#' | sed 's/#.\+//' | perl -lane 'printf \"%s=%s:\", shift @F, join \";\", @F;'"
Now reload your config file '$ . ~/.bashrc'
And let's see what aliases we have, you should see your newly created alias, run the command '$ alias' to see a listing.
We can now use that as a filter on the command line.
- b) Save it to a bash script
- Edit a file in your ~/bin directory.. make sure it's got execute permissions..
$ vim ~/bin/string2lscolors $ cat ~/bin/string2lscolors #!/bin/sh grep '\w' | grep -v '^#' | sed 's/#.\+//' | perl -lane 'printf "%s=%s:", shift @F, join ";", @F;' $ chmod 0755 ~/bin/string2lscolors
Awesome, now you can call the command 'string2lscolors' anywhere you want.
To try it out, do the above steps, and you can download my example human legible format file, and try it out..
$ wget http://leocharre.com/docs/lscolorscheme.txt -O /tmp/lscolorscheme.txt $ cat /tmp/lscolorscheme.txt | string2lscolors no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;91:*.cmd=00;32:*.exe=00;32:*.gz=00;90:*.bz2=00;90:*.bz=00;90:*.tz=00;90:*.rpm=00;90:*.rar=00;90:*.zip=00;90:*.iso=00;90:*.cpio=00;31:*.c=33:*.h=33:*.sh=33:*.t=33:*.pm=33:*.pl=33:*.cgi=33:*.pod=33:*.PL=33:*.js=33:*.php=33:*.off=00;9:*.bak=00;9:*.old=00;9:*.htm=94:*.html=94:*.txt=94:*.text=94:*.css=94:*.avi=96:*.wmv=96:*.mpeg=96:*.mpg=96:*.mov=96:*.AVI=96:*.WMV=96:*.mkv=96:*.jpg=96:*.jpeg=96:*.png=96:*.xcf=96:*.JPG=96:*.gif=96:*.svg=96:*.eps=00;96:*.pdf=00;96:*.PDF=00;96:*.ps=00;96:*.ai=00;91:*.doc=00;91:*.csv=95:*.dsv=95:*.db=95:*.sql=95:*.meta=95:*.xml=95:*.yaml=95:*.yml=95:*.conf=95:
- c) You can make sure the thing is presented kind of decent, writing a minimal program..
- This means a few things.. One for damn sure, that if I ask for --help, I get help. There are no conditions about this. It simply has to be there. If you can't assure your programs at least have the appropriate help docs- you should not be writing software, unless you're using microsoft type environments, then- knock yourself out- You won't be heard from again.
The reason is that in any sort of interface- you must present your users with what they are already familiar with. This is explained in The Rule of Least Surprise. And by the way- those rules there, the basics of the unix philosophy.. Those are not little poems- those the FUCKING RULES, maggot! It's what separates the women from the little girls. You don't have to always abide by all of them- but you must aspire to at *least* make note of most of them.
If you're having any doubts about the supremacy of unix philosophy- please, read those rules, carefully, slowly. If you're still in doubt, consider that programs written in unix shell ten or twenty years ago, still work today.
This is how you would write the same one liner up there, as a more useful program.. Again, this is minimal, but you can see that instead of two lines we have 117.. See string2LS_COLORS.sh.
- Using the filter to automatically edit your ~/.bashrc..
- Making this a simple filter..
All you need to do to see it change before your eyes, is to go to a command line prompt, and type in:
$ LS_COLOR='di=00:fi=00;1:*.php=00;34' $ ls
You'll notice that makes all regular files appear bold, all directories in 'normal text weight' and default color (black on white, white on black)- and php files are blue (or whatever color is mapped to that slot).
Now, if you wanted to make that change permanent (instead of only to that one terminal session you just opened)- you would enter that into your ~/.bashrc file .. as:
My personal LS_COLOR environment variable for perl development- I have refined mine to be:
This helps me detect some things that are important to me, such as tests.t to stand out from other junk in t/, a different color for pod and pm files.. etc. very cool.
I've been using this across my servers. And it does help. It's a very small thing to do, to improve your development environment. I suggest you try it out.