¿Cómo fusionar los colores de los comandos ls con la salida de find o du?

¿Cómo fusionar los colores de los comandos ls con la salida de find o du?

Tengo un alias simple para enumerar el tamaño de archivos y carpetas en cwd.

(incluidos los archivos de puntos en este caso, ignorando los tamaños cero)

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

que también se puede lograr con find:

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

salida de ejemplo:

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

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

¿Cómo puedo colorear los archivos/directorios en la salida que coincidan con los colores de ls?(LS_COLORS)

Respuesta1

Este zshscript analiza $LS_COLORS. Sólo necesita una statllamada a cada archivo y, por lo tanto, es mucho más rápida que la solución en la parte inferior, que llama lsa cada archivo. Y maneja archivos con espacios correctamente. ( \no \ttodavía estánnopermitido en nombres de archivos)

Sin embargo, la implementación no está completa. Sólo incluí colores para diferentes tipos de archivos que pueden identificarse por el primer carácter de la cadena del modo de archivo (por ejemplo, lrwxrwxrwxpara un enlace simbólico) o por la extensión del archivo. Esto significa que los permisos de escritura mundial, los bits suid o adhesivos no tienen colores especiales. Incluirlos también debería ser sencillo.

sourcelo siguiente y use la nueva función Shell ducpara una dusalida en color:

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 es mi antiguo script, también para zsh. Probablemente sea innecesariamente complejo y muy lento, ya que para cada archivo lsse emite un único comando:

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))]}
  }
}
  • el .*en zshvoluntadnocoincide con .o .., pero archivos como ..fooel cual se perderán con.[!.]*
  • typeset -adeclara una matriz
  • los bucles for aver la matriz, $itoma valores de 1 en adelante en pasos de 2

Advertencia: Esto se romperá gravemente cuando haya archivos conespacios en blanco... No tengo una mejor idea en este momento.

Respuesta2

Esto es lo que se me ocurrió para bash: usa pv para mostrar el progreso de la salida

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
}

El script ahora se puede convertir en una sola línea... pero mejoraré la función agregando indicadores para, por ejemplo, 10 archivos/carpetas más grandes o solo carpetas.

Respuesta3

Esto funciona para mí:

#!/usr/bin/env bash

paste <(du --apparent-size --all --human-readable --max-depth=1 2>/dev/null |
    sed 's/\s.*//') \
    <(ls --color=always -1 --almost-all -U) | sort --human-numeric-sort

El comando principal aquí es pasteunirá las salidas de lsy duhorizontalmente.

dugenerará cada línea algo como esto:

147291    ./.config

sed 's/\s.*//eliminará todo lo que sigue al primer espacio incluido, es decir, ./.configya que no estamos interesados ​​en las formas sin color de los nombres de las entradas enumeradas. El truco aquí es generar lsel contenido del directorio de la misma manera dupara que podamos unir sin esfuerzo cada entrada con su tamaño correspondiente. Podemos hacerlo con la ayuda de -1(que enumera las entradas verticalmente en lugar de horizontalmente), -U(que enumera las entradas en orden de directorio, como duen lugar de alfabéticamente) y --almost-all(que también enumera directorios/archivos ocultos, pero omite .y ..en lugar de --all) y por supuesto --color=always. Para du, --alles necesario hacer que procese tanto archivos (incluidos los ocultos) como directorios en lugar de solo directorios, y --max-depth=1deja dude operar en subdirectorios (como finden -maxdepth 1)

Entonces, para responder a la pregunta, sólo se necesita lo siguiente:

paste <(du --all --max-depth=1 | sed 's/\s.*//') \
    <(ls --color=always -1 --almost-all -U)

En cuanto a los otros argumentos opcionales:

  • --apparent-sizehace que dulos tamaños de impresión sean aparentes, en lugar del uso del disco (mi preferencia)
  • --human-readableimprime tamaños legibles por humanos
  • 2>/dev/nullfiltra cualquier permission deniederror si intentó ejecutar duen un directorio restringido, por ejemplo/var
  • sort --human-numeric-sortclasifica los tamaños en orden descendente, --human-numeric-sortes necesario si --human-readablese pasa adu

Respuesta4

La combinación de algunas de las respuestas anteriores con oh-my-zshell en una Mac me proporcionó tamaños, nombres de directorios coloreados y nombres de archivos de texto sin formato ordenados para generar los 10 archivos/directorios más grandes:

paste <(du -cks *) <(ls --color=always -1) | sort -nr | head | awk '{print $1 "  " $3}'

Explicación:
dupara el uso del disco -c:grand total -k: 1Kb blocks -s: entrypara cada archivo;
lstomar el color de los directorios;
pastecombinar ambos resultados anteriores;
sort -nr: clasificación inversa numérica;
head: genera archivos/directorios más grandes;
awk: para generar solo la primera columna (tamaño) y la tercera columna (nombre de archivo/directorio coloreado)

información relacionada