Как объединить цвета команд ls с выводом find или du?

Как объединить цвета команд ls с выводом find или du?

У меня есть простой псевдоним для вывода размера файлов и папок в cwd.

(включая dotfiles в этом случае, игнорируя нулевые размеры)

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

что также может быть достигнуто с помощью find:

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

пример вывода:

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

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

Как раскрасить файлы/каталоги в выводе в соответствии с цветами ls?( LS_COLORS )

решение1

Этот zshскрипт анализирует $LS_COLORS. Ему нужен только statвызов для каждого файла, и поэтому он намного быстрее, чем решение внизу, которое вызывает lsкаждый файл. И он правильно обрабатывает файлы с пробелами. ( \nили\t все ещенетразрешено в именах файлов)

Однако реализация не завершена. Я включил цвета только для разных типов файлов, которые можно определить по первому символу строки режима файла (например, lrwxrwxrwxдля символической ссылки) или по расширению файла. Это означает, что разрешения на запись для всех, suid или sticky биты не окрашены специально. Включить их также должно быть просто.

sourceследующее и используйте новую функцию оболочки ducдля цветного duвывода:

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
  }
}

Это мой старый скрипт, тоже для . Он, вероятно, излишне сложен и очень медленный, так как для каждого файла выдается zshодна команда: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))]}
  }
}
  • в .*волеzshнетсоответствует .или .., но файлы, подобные ..fooкоторым, будут пропущены с.[!.]*
  • typeset -aобъявляет массив
  • циклы for для массива, $iпринимают значения от 1 и далее с шагом 2

Предупреждение: Это приведет к серьезным сбоям, если есть файлы спробелы... На данный момент у меня нет лучшей идеи.

решение2

Вот что я придумал для bash — использует pv для отображения прогресса вывода

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
}

Теперь скрипт можно превратить в однострочный... но я улучшу функцию, добавив флаги, например, для 10 самых больших файлов/папок или только для папок.

решение3

Мне это подходит:

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

Основная команда здесь — paste, она объединит выходы lsи duпо горизонтали.

duвыведет каждую строку примерно так:

147291    ./.config

sed 's/\s.*//удалит все после и включая первый пробел, т.е. ./.configпоскольку нас не интересуют неокрашенные формы имен перечисленных записей. Хитрость здесь в том, чтобы сделать lsвывод содержимого каталога таким же образом, как duи так, чтобы мы могли без усилий объединить каждую запись с ее соответствующим размером. Мы можем сделать это с помощью -1(который перечисляет записи вертикально, а не горизонтально), -U(который перечисляет записи в порядке каталога, как du, а не в алфавитном порядке) и --almost-all(который перечисляет скрытые каталоги/файлы, но исключает .и ..в отличие от --all) и, конечно же --color=always. Для du, --allнеобходимо заставить его обрабатывать как файлы (включая скрытые), так и каталоги, а не только каталоги, и --max-depth=1прекратить duработу с подкаталогами (как find's -maxdepth 1)

Итак, чтобы ответить на вопрос, необходимо лишь следующее:

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

Что касается других необязательных аргументов:

  • --apparent-sizeделает duпечать видимых размеров, а не использования диска (мое предпочтение)
  • --human-readableпечатает размеры, удобные для восприятия человеком
  • 2>/dev/nullотфильтровывает любые permission deniedошибки, если вы попытались запустить duв ограниченном каталоге, например/var
  • sort --human-numeric-sortсортирует размеры в порядке убывания, --human-numeric-sortнеобходимо, если --human-readableпередаетсяdu

решение4

Объединение некоторых из приведенных выше ответов с oh-my-zshell на Mac дало мне размеры, цветные имена каталогов и имена файлов в виде обычного текста, отсортированные для вывода 10 самых больших файлов/каталогов:

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

Пояснение:
duдля использования на диске -c:grand total -k: 1Kb blocks -s: entryдля каждого файла;
lsдля захвата цвета для каталогов;
pasteдля объединения обоих вышеуказанных выходных данных;
sort -nr: числовая обратная сортировка;
head: выводит самые большие файлы/каталоги;
awk: выводит только первый столбец (размер) и 3-й столбец (имя файла/раскрашенного каталога)

Связанный контент