Is there a straightforward way to color ls output according to Finder label colors in macOS?

Color information is available from the com.apple.FinderInfo extended attribute.

$ xattr -p com.apple.FinderInfo filename
00 00 00 00 00 00 00 00 00 0C 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

First row, tenth byte, bits 3-1 (i.e. those with binary values 2, 4 and 8). The example output is for a red file with no other values set.

If the attribute isn't available or the nibble is 0, it's colorless.

Possible values in context-menu order from left to right: 0 (colorless), C (red), E, A, 4, 8, 6, 2 (gray).

Remember to check for possible 1 values for that last bit, i.e. 3 would also be gray + some other attribute.


One possible solution would be the following:

Define a function ls in ~/.bash_profile that does something slightly different if no parameters are given:

function ls {
        if [ "$#" = "0" ] ; then
                find . -maxdepth 1 -exec ~/Library/Scripts/colorize.sh '{}' \;
        else
                $( which ls ) $@
        fi
}       

colorize.sh could look like the following, calling a Python script and printing the filename depending on its output:

#!/bin/bash

filename=$1

if [ ! -e "$filename" ] ; then
    exit
fi

filename="$( basename "$filename" )"

attrs=( $( $( dirname $0 )/attrs.py "$filename" | cut -f2 ) )

hidden=${attrs[0]}

if [ "$hidden" = "True" ] ; then
    exit
fi

color=${attrs[1]}

case "$color" in
    "none" )
        format="setab 8"
        ;;
    "red" )
        format="setab 1"
        ;;
    "orange" )
        format="setab 1"
        ;;
    "yellow" )
        format="setab 3"
        ;;
    "green" )
        format="setab 2"
        ;;
    "blue" )
        format="setab 4"
        ;;
    "purple" )
        format="setab 5"
        ;;
    "gray" )
        format="setab 7"
        ;;
esac

echo "$( tput $format )$filename$( tput sgr0 )"

And attrs.py, which extracts relevant file attributes, in the same directory:

#!/usr/bin/env python

from sys import argv, exit
from xattr import xattr
from struct import unpack

if len(argv) < 2:
    print('Missing filename argument!')
    exit(1)

attrs = xattr(argv[1])

try:
    finder_attrs= attrs[u'com.apple.FinderInfo']

    flags = unpack(32*'B', finder_attrs)

    hidden = flags[8] & 64 == 64
    color = flags[9] >> 1 & 7
except:
    hidden = False
    color = 0

colornames = { 0: 'none', 1: 'gray', 2 : 'green', 3 : 'purple', 4 : 'blue', 5 : 'yellow', 6 : 'red', 7 : 'orange' }

print 'hidden:\t', hidden
print 'color:\t', colornames[color]

I didn't have a large enough matching color selection here, so red and orange are both printed in red.

enter image description here

enter image description here

I added the hidden attribute here since I am interested in that part of modifying ls output. Just remove the if statement if you don't want it.