A few years ago I found an interesting code snippet that prints each type of file in its corresponding color according to the colors set up in LS_COLORS. Unfortunately, I can't remember the link anymore.

Here is the snippet test_colors.sh in question

eval $(echo "no:global default;fi:normal file;di:directory;ln:symbolic link;pi:named pipe;so:socket;do:door;bd:block device;cd:character device;or:orphan symlink;mi:missing file;su:set uid;sg:set gid;tw:sticky other writable;ow:other w\
ritable;st:sticky;ex:executable;"|sed -e 's/:/="/g; s/\;/"\n/g')                                                                                                                                                                            
  for i in $LS_COLORS                                                                                                                                                                                                                       
    echo -e "\e[${i#*=}m$( x=${i%=*}; [ "${!x}" ] && echo "${!x}" || echo "$x" )\e[m"                                                                                                                                                       

The snippet works great in bash, but not in zsh, and I can't tell why. When I run it in zsh I get the following error:

> sh .test_colors.sh
.eval_colors:1: * not found

Update (Nov. 1, 2011)

I tested the script by @Stéphane Gimenez below. I noticed that some characters seem to not escape correctly. Any thoughts why?

Answer: See comments on @Stéphane Gimenez's answer.

                                                      enter image description here


The same written for zsh in a much cleaner way:


typeset -A names
names[no]="global default"
names[fi]="normal file"
names[ln]="symbolic link"
names[pi]="named pipe"
names[bd]="block device"
names[cd]="character device"
names[or]="orphan symlink"
names[mi]="missing file"
names[su]="set uid"
names[sg]="set gid"
names[tw]="sticky other writable"
names[ow]="other writable"

for i in ${(s.:.)LS_COLORS}
    printf '\e[%sm%s\e[m\n' $color $name
  • You might want to replace \n by a space at the end of the printf for compactness maybe. – Stéphane Gimenez Sep 15 '11 at 0:27
  • Thanks @Stéphane Gimenez. I have updated my OP with a problem I am getting when printing some characters using your script. Not sure if this is strictly related to your script though (it may be my own terminal?) – Amelio Vazquez-Reina Nov 1 '11 at 18:09
  • 1
    @intrpc: running zsh as sh your are using some compatibility mode. Either call your script as zsh ./test_color_scheme or add double quotes around $color and $name. – Stéphane Gimenez Nov 2 '11 at 12:35
  • @Stéphane Gimenez: I was directed here from my related question here: unix.stackexchange.com/questions/52659/… . Your expansion of abbreviations is very helpful. I have three abbreviations, rs, ca and mh that are not included above. Can you please tell me where to find their expansions? Thanks. – chandra Oct 24 '12 at 5:13
  • Interpreted from dircolors -p rs=reset, ca=capability, mh=multi-hard_link – weldabar Nov 3 '13 at 20:16

You need to escape the = in ${i%=*} because otherwise the suffix pattern =* undergoes = expansion, so = is interpreted as a command name. This is the cause of the * not found error.

Zsh doesn't split words on variable substitutions by default, so $LS_COLORS expands to a single word. To have the for loop operate on the colon-separated parts of $LS_COLORS, use for i in $=LS_COLORS. Or more idiomatically in zsh, don't use IFS but instead specify explicitly how to split: for i in ${(s.:.)LS_COLORS}.

The syntax ${!x} to mean “the value of the variable whose name is $x” is specific to bash. Zsh has an equivalent construct, the P parameter expansion flag: ${(P)x}.

  • 1
    There are two more reasons for this script is not working in zsh. No automatic word-splitting for LS_COLORS and = needs to be escaped in substitution patterns. – Stéphane Gimenez Sep 15 '11 at 0:54
  • @StéphaneGimenez You're right, thanks, I only hit on where bash is non-standard but these are two non-standard zsh features that need to be addressed as well. You should expand your answer to have all the explanations, and then I can delete mine. – Gilles 'SO- stop being evil' Sep 15 '11 at 7:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.