Mac OS X: Existe uma maneira simples de imprimir a saída ls de acordo com as cores das etiquetas do Finder?

6

Eu tenho um cliente com uma árvore de diretórios que possui vários diretórios de alto nível que eu preciso ter em minha máquina de desenvolvimento local. Eu raramente olho para eles a menos que algo dê errado.

Eu marquei os "desinteressantes" com o rótulo de cor cinza e os que eu uso diariamente com um rótulo de cor verde no Finder. Isso funciona bem nas raras ocasiões em que estou usando o Finder.

Em vez disso, eu uso o Terminal.app, embora eu não seja contra outros emuladores de terminal, desde que eles sejam rápidos e robustos. Ao usar ls, mesmo com os sinalizadores @ e G, não tenho informações úteis que possam ser usadas para não enfatizar as entradas de diretório desinteressantes. (Se eu pudesse canalizar sls através de um simples script awk para aplicar coloração, eu ficaria bem com isso.)

Estou ciente de que posso usar o osascript para obter esse atributo e, em seguida, decorar a saída do arquivo, mas isso provavelmente resultará na implementação mais lenta do ls desde o Unicos. Eu também sei que posso mudar as cores padrão com ls, mas isso não chega ao nível que eu preciso.

Existe uma ferramenta simples e rápida que já existe e que irá colorir a saída ls com base nas cores das etiquetas do Finder, e então voltar para $ LSCOLORS? Ou esse é o meu próximo projeto do github? : -)

Obrigado!

    
por Art Taylor 09.06.2011 / 20:18

2 respostas

15

As informações de cor estão disponíveis no atributo com.apple.FinderInfo extended.

$ 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

Primeira linha, décimo byte, bits 3-1 (isto é, aqueles com valores binários 2, 4 e 8). O exemplo de saída é para um arquivo vermelho sem nenhum outro conjunto de valores.

Se o atributo não estiver disponível ou o nibble for 0 , ele será incolor.

Valores possíveis na ordem do menu de contexto da esquerda para a direita: 0 (incolor), C (vermelho), E , A , 4 , 8 , 6 , 2 (cinza).

Lembre-se de verificar possíveis valores de 1 para o último bit, ou seja, 3 também seria cinza + algum outro atributo.

Uma solução possível seria a seguinte:

Defina uma função ls in ~/.bash_profile que faz algo ligeiramente diferente se nenhum parâmetro for fornecido:

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

colorize.sh poderia ser semelhante ao seguinte, chamando um script Python e imprimindo o nome do arquivo, dependendo da saída:

#!/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 )"

E attrs.py , que extrai atributos de arquivo relevantes, no mesmo diretório:

#!/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]

Eu não tenho uma seleção de cores grande o suficiente aqui, então vermelho e laranja são ambos impressos em vermelho.

Adicionei o atributo hidden aqui, pois sou interessado nessa parte da modificação de ls output. Apenas remova a instrução if se você não quiser.

    
por 09.06.2011 / 20:30
1

Obrigado a @DanielBeck por sua resposta detalhada.

Aqui está uma solução muito rápida e suja, útil para verificar rapidamente o rótulo de algum arquivo no ssh:

#!/bin/bash

color_08=$'\e[44;30m' #blue
color_02=$'\e[47;30m' #gray
color_04=$'\e[42;30m' #green
color_0E=$'\e[46;30m' #orange/cyan
color_06=$'\e[45;30m' #purple
color_0C=$'\e[41;30m' #red
color_0A=$'\e[43;30m' #yellow
color_00=$'\e[m'
end=$'\e[K\e[m'

for f in *; do
    x=$(xattr -p com.apple.FinderInfo "$f" 2>/dev/null)
    x=${x:27:2}
    x=color_${x:-00}
    echo "${!x}$f$end"
done

Aviso: não use isso em nenhuma forma ou formato profissional, nem o use em nenhum arquivo fornecido por outra pessoa, porque ele usa a indireta do shell, que é tão ruim quanto a eval.

Além disso, as cores foram escolhidas para o meu esquema de cores específico (Luz Solarizada). Você pode precisar ajustar as seqüências de escape para se adequar ao seu esquema.

Aqui está uma pasta de teste:

Eaquiestácomoficaomeuscript:

A laranja se torna ciana, porque é isso que o terminal fornece.

E sim, é 2016 e eles terão que tirar o OS X 10.8 dos meus dedos frios e mortos: -)

    
por 29.01.2016 / 22:52