Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I had asked this question a while back: Is it possible to colorize permissions-part of the output of ls?

While the accepted answer in that question is OK, I now want to do the same thing without using any "external" language. I came up with the following using a bash function and sed.

The question is can you help me fix one bug and also help me make this code "better" ?

  • Make better: I am repeating \([r-]\)\([w-]\)\([x-]\)\ three times. How to make this more succint?
  • Fix bug: I am unable to get a back-reference to the tenth match \10. Does sed only support up to 9 back-references?

    enter image description here

The relevant portion of the code (broken into multiple lines for purposes of better readability when posting in this question):

ls -la | sed "s
`echo -e \"

For reference, the complete function I am using is:

domagic() {
  local NONE="\033[0m"    # unsets color to term's fg color

  # regular colors
  local K="\033[0;30m"    # black
  local R="\033[0;31m"    # red
  local G="\033[0;32m"    # green
  local Y="\033[0;33m"    # yellow
  local B="\033[0;34m"    # blue
  local M="\033[0;35m"    # magenta
  local C="\033[0;36m"    # cyan
  local W="\033[0;37m"    # white

  # emphasized (bolded) colors
  local EMK="\033[1;30m"
  local EMR="\033[1;31m"
  local EMG="\033[1;32m"
  local EMY="\033[1;33m"
  local EMB="\033[1;34m"
  local EMM="\033[1;35m"
  local EMC="\033[1;36m"
  local EMW="\033[1;37m"

  # background colors
  local BGK="\033[40m"
  local BGR="\033[41m"
  local BGG="\033[42m"
  local BGY="\033[43m"
  local BGB="\033[44m"
  local BGM="\033[45m"
  local BGC="\033[46m"
  local BGW="\033[47m"

  #do magic here
  ls -la | sed "s/^\([d-]\)\([r-]\)\([w-]\)\([x-]\)\([r-]\)\([w-]\)\([x-]\)\([r-]\)\([w-]\)\([x-]\)/`echo -e \"$EMG\1$EMY\2\3\4$EMR\5\6\7$EMC\8\9\10$NONE\"`/"
#to run: save as domagic.sh and run with: bash domagic.sh
share|improve this question
add comment

2 Answers 2

up vote 3 down vote accepted

Sed supports up to 9 backreferences, but observing that \2\3\4 go always together, as do \5\6\7 and \8\9\10, you can use only four groups, like in the following:

"s/^\([d-]\)\([r-][w-][x-]\)\([r-][w-][x-]\)\([r-][w-][x-]\)/`echo -e \"$EMG\1$EMY\2$EMR\3$EMC\4$NONE\"`/""
share|improve this answer
Thanks. I just came up with the exact same result :). Now the problem of making it without having to repeat the character classes remains. Accepting this answer for the "bug fix",though! –  Zabba Oct 23 '11 at 20:57
To be shorter you can use \([d-]\)\(.\{3\}\)\(.\{3\}\)\(.\{3\}\) or even \([d-]\)\(...\)\(...\)\(...\), but cannot avoid three patterns, having to apply different colors. –  enzotib Oct 24 '11 at 5:39
add comment

You're calling sed from bash, so you can use bash to avoid repeating the character classes. Everything inside double quotes gets expanded:

ls -la | sed "s/^\([d-]\)$rwx$rwx$rwx/`echo -e \"$EMG\1$EMY\2\3\4$EMR\5\6\7$EMC\8\9\10$NONE\"`/"

But I don't think looking for drwx is quite right. What if the file is a symlink? That will start with l. And if it's a "sticky" directory (e.g. /tmp), that will end with t instead of x, etc.

Why not just

ls -la | sed "s/^\(.\)\(...\)\(...\)\(...\)/`echo -e \"$EMG\1$EMY\2$EMR\3$EMC\4$NONE\"`/""

Finally, if you change how you declare your colors, you don't need the echo -e:

domagic() {
  local NONE=$'\033[0m'    # unsets color to term's fg color

  # regular colors
  local K=$'\033[0;30m'    # black
  local R=$'\033[0;31m'    # red
  local G=$'\033[0;32m'    # green
  local Y=$'\033[0;33m'    # yellow
  local B=$'\033[0;34m'    # blue
  local M=$'\033[0;35m'    # magenta
  local C=$'\033[0;36m'    # cyan
  local W=$'\033[0;37m'    # white

  # emphasized (bolded) colors
  local EMK=$'\033[1;30m'
  local EMR=$'\033[1;31m'
  local EMG=$'\033[1;32m'
  local EMY=$'\033[1;33m'
  local EMB=$'\033[1;34m'
  local EMM=$'\033[1;35m'
  local EMC=$'\033[1;36m'
  local EMW=$'\033[1;37m'

  # background colors
  local BGK=$'\033[40m'
  local BGR=$'\033[41m'
  local BGG=$'\033[42m'
  local BGY=$'\033[43m'
  local BGB=$'\033[44m'
  local BGM=$'\033[45m'
  local BGC=$'\033[46m'
  local BGW=$'\033[47m'

  #do magic here
  ls -la | sed "s/^\(.\)\(...\)\(...\)\(...\)/$EMG\1$EMY\2$EMR\3$EMC\4$NONE/"
share|improve this answer
add comment

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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