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)

    
por nifr 09.06.2013 / 00:27

2 respostas

1

Este script zsh analisa $LS_COLORS . Ele precisa apenas de uma chamada stat em todos os arquivos e, portanto, é muito mais rápido que a solução na parte inferior, que chama ls para cada arquivo. E lida com arquivos com espaços corretamente. ( \n ou \t ainda não são permitidos 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 do 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 do seguinte e use a nova função do shell duc para uma% coloridadu output:

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 script antigo, também para zsh . Ele provavelmente é desnecessariamente complexo e é muito lento, já que para cada arquivo é emitido um único comando ls :

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))]}
  }
}
  • o .* em zsh não corresponde a . ou .. , mas arquivos como ..foo , que serão perdidos com .[!.]*
  • typeset -a declara uma matriz
  • os loops for aver a matriz, $i recebe valores de 1 em diante em etapas de 2

Aviso : Isso quebrará quando houver arquivos com espaços em branco ... Não tenho uma ideia melhor no momento.

    
por 09.06.2013 / 01:27
1

Isto é o que eu criei 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 linha única ... mas melhorarei a função adicionando sinalizadores para os 10 maiores arquivos / pastas ou pastas apenas.

    
por 10.06.2013 / 02:41