如何将 ls 命令颜色与 find 或 du 的输出合并?

如何将 ls 命令颜色与 find 或 du 的输出合并?

我有一个简单的别名来列出 cwd 中文件和文件夹的大小。

(在这种情况下包括点文件,忽略零尺寸)

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_颜色)

答案1

zsh脚本解析$LS_COLORS。它只需要stat对每个文件进行一次调用,因此比底部ls对每个文件进行调用的解决方案快得多。并且它可以正确处理带有空格的文件。(\n\t仍然不是允许在文件名中使用)

但是,实现并不完整。我只包括了不同文件类型的颜色,这些文件类型可以通过文件模式字符串的第一个字符(例如lrwxrwxrwx符号链接)或文件扩展名来识别。这意味着,全球可写权限、suid 或 sticky 位没有特殊颜色。包括这些也应该很简单。

source以下内容并使用新的 shell 函数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不是匹配...,但像..foowhich 这样的文件将会丢失.[!.]*
  • 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的输出。lsdu

du每行都会输出如下内容:

147291    ./.config

sed 's/\s.*//将删除第一个空格之后的所有内容,即./.config因为我们对所列条目名称的非彩色形式不感兴趣。这里的技巧是使ls目录的内容以与相同的方式输出,du以便我们可以轻松地将每个条目与其相应的大小连接起来。我们可以借助-1(垂直列出条目而不是水平列出条目),-U(按目录顺序列出条目,就像du,而不是按字母顺序排列)和--almost-all(也列出隐藏目录/文件,但省略了...而不是--all)以及当然来做到这一点--color=always。对于du--all需要使其处理文件(包括隐藏文件)和目录而不仅仅是目录,并--max-depth=1停止du对子目录进行操作(就像find-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/nullpermission denied如果您尝试du在受限目录中运行,则会过滤掉所有错误,例如/var
  • sort --human-numeric-sort按降序对大小进行排序, --human-numeric-sort如果--human-readable传递给du

答案4

将上述一些答案与 Mac 上的 oh-my-zshell 结合起来,为我提供了大小、彩色目录名和纯文本文件名,并按排序输出了 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

相关内容