Como mesclar as cores dos comandos ls com a saída de find ou du?

1

Eu tenho um alias simples para listar o tamanho dos arquivos e pastas em cwd.

(incluindo dotfiles neste caso, ignorando tamanhos zero)

du -sh .[!.]* * | sort -hr | grep -v '^0'

que pode ser alcançado também com o find:

find .[!.]* * -maxdepth 0 -exec du -sh {} \; | sort -hr | grep -v '^0'

exemplo de saída:

// .ssh & .byobu are folders - .zsh* are files
// currently not able to distinguish them by type

... 
32K     .zshrc
25K     .ssh
20K     .zcompdump
19K     .byobu
...

Como posso colorir os arquivos / diretórios na saída correspondente às cores ls? (LS_COLORS)

nifr
fonte
Eu não posso ver porque isso não funciona - isso acontece com um print, mas fica mutilado com o system: du -sh .[!.]* * | sort -hr | grep -v '^0' | awk '{print $1;system( "ls -d --color '$2'") }'
Paul
isso definitivamente aponta para a direção certa ... A saída é colorida (todos com a cor dir de ls) ... mas todos os arquivos / pastas são transformados em "/ n". . obrigado por seus esforços - eu percebo que a solução provavelmente será um truque / awk complicado! :)
nifr
você também pode usar a opção --color disponível para o grep .... eg: `find. -iname "t *" | du -sh * | grep stuff --color = auto`
n13
Obrigado - eu já tenho grep aliased para grep --color=auto ... grep destacará um string de pesquisa / padrão na saída ... mas não divide entre arquivos & amp; pastas na saída usando o LS_COLORS. Obrigado pela dica de qualquer maneira :)
nifr

Respostas:

1

este zsh script analisa $LS_COLORS. Precisa apenas de um stat chamar todos os arquivos e, portanto, é muito mais rápido do que a solução na parte inferior, que chama ls para cada arquivo. E lida com arquivos com espaços corretamente. ( \n ou \t continuam a ser não permitido em nomes de arquivos)

No entanto, a implementação não está completa. Eu incluí apenas cores para diferentes tipos de arquivos que podem ser identificados pelo primeiro caractere da string de modo de arquivo (por exemplo, lrwxrwxrwx para um link simbólico) ou pela extensão do arquivo. Isso significa que as permissões graváveis ​​do mundo, suid ou bits pegajosos não são coloridas especialmente. Para incluir esses também deve ser direto.

source o seguinte e use a nova função shell duc para um colorido du saída:

zmodload -F zsh/stat b:zstat

function duc() {

  emulate zsh 
  setopt no_nomatch interactivecomments           # no_nomatch is necessary, to prevent error in "do .* *" if there are no dotfiles

  typeset -a aline
  typeset -A lscols
  local dircols acolor

  for i (${(s.:.)LS_COLORS}) {                    # split $LS_COLORS at ":"
    aline=(${(s:=:)i})                            # split every entry at "="
    lscols+=(${${aline[1]}/*.} ${aline[2]})       # load every entry into the associative array $lscols
  }

  duout=$(du -sh .* * 2> /dev/null | grep -v '^0' | sort -hr)
  for i (${(f)duout}) {                           # split output of "du" at newlines
    aline=(${(ps:\t:)i})                          # split every entry at \t
    zstat -s +mode -A atype ${aline[2]}           # determine mode (e.g. "drwx------") of file ${aline[2]}
    case ${${atype[1]}[1]} in                     # ${${atype[1]}[1]} is the first character of the file mode
      b)   acolor=$lscols[bd] ;;
      c|C) acolor=$lscols[cd] ;;
      d)   acolor=$lscols[di] ;;
      l)   acolor=$lscols[ln] ;;
      p)   acolor=$lscols[pi] ;;
      s)   acolor=$lscols[so] ;;
      -)   acolor=${lscols[${${aline[2]}:e}]};      # ${${aline[2]}:e} is the current file extention
           [[ -z $acolor ]] && acolor=$lscols[fi]   # unrecognized extention
           [[ -z $acolor ]] && acolor=00            # sometimes "fi" isn't set in $LS_COLORS, so fall back to normal color
           ;;
      *)   acolor=00 ;;
    esac
    print -n -- "${aline[1]}\t"        # print size (taken from du output)
    print -n "\\e[4${acolor}m"         # activate color
    print -n ${aline[2]}               # print file name
    print "\\e[0m"                     # deactivate color
  }
}

Este é o meu antigo roteiro, também para zsh. Provavelmente é desnecessariamente complexo e é muito lento, pois para cada arquivo um único ls comando é emitido:

du_colored() {
  typeset -a duout
  duout=($(du -sh .* * | sort -hr | grep -v '^0'))
  for i ({1..$#duout..2}) {
    print -n "${duout[$i]}\t"
    ls -d --color ${duout[$(($i+1))]}
  }
}
  • a .* em zsh vai não partida . ou .., mas arquivos como ..foo que será perdido com .[!.]*
  • typeset -a declara uma matriz
  • os loops for sobre o array, $i leva valores de 1 em diante em etapas de 2

Aviso : Isso vai quebrar mal quando houver arquivos com espaços em branco ... Eu não tenho uma ideia melhor no momento.

mpy
fonte
+1 para esta ser a primeira solução quase em funcionamento. executar ls para cada arquivo parece um exagero. simplesmente combinando um ls -a --colors (exibindo as cores) contra a segunda string (folder / filename sem cor) na saída de du teria mais desempenho. tentando alcançá-lo, mas não consegue encontrar um caminho suficiente ainda: /
nifr
ls -a --color | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" remove as cores - agora como podemos substituir o du saída com a saída colorida de ls -a --color ? :)
nifr
@nifr: adicionei outro script, que analisa $LS_COLORS diretamente. Isso é muito mais rápido do que o meu hack de mais de meia-noite de ontem, já que ele precisa apenas registrar todos os arquivos em vez de executar ls.
mpy
Agradecimento além disso - eu hackeei uma solução para o bash ontem em uma sessão noturna - postarei abaixo, talvez você possa revisá-la :)
nifr
1

Isto é o que eu inventei para o bash - usa pv para mostrar o progresso da saída

folder_size (){
  # read ls --color output into ls_colored_array 
  # thereby remove symlinks (@) and remove (/ and *) from folders and files

  ls -AF --color | grep -v @ | sed s'/[/\,*]$//'| xargs -n1 -L1 | read -d '\n' -r -a ls_colored_array

  # - loop over the array and issue du -sh for every element
  # - exchange du's ouput with ls's 
  # - run loop through pv with line option and
  #    size set to array-length showing progress
  # - finally sort the output using sort

  for i in "${ls_colored_array[@]}"; do
    echo -n "${i}" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | xargs -n1 -0 du -sh | awk -v i="$i" '{ printf "%-10s ", $1; $1=""; print i }'
  done | pv -pls"${#ls_colored_array[@]}" | sort -hr
}

Agora, o script pode ser transformado em uma única linha ... mas melhorarei a função adicionando sinalizadores, ou seja, 10 arquivos / pastas ou pastas maiores apenas.

nifr
fonte
Esta é uma boa solução, especialmente aquela parte com a barra de progresso, +1 para isso :) No entanto, eu tive que mudar a linha de leitura para read -d '\n' -r -a ls_colored_array <<< $(ls -AF --color | grep -v @ | sed s'/[/\,*]$//'| xargs -n1 -L1) para fazê-lo funcionar na planície bash (relacionado: superuser.com/questions/173337/… ). Infelizmente este script quebra em espaços em branco nos nomes dos arquivos. (Eu suponho que você precisa usar um contador para acessar todo o $ls_colored_array elementos em vez de passar a matriz diretamente para o loop for).
mpy