如何將 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 或黏性位元不會被特殊著色。包含這些也應該是直截了當的。

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意願不是匹配...,但類似的文件..foo將被錯過.[!.]*
  • typeset -a聲明一個數組
  • for 迴圈平均數組,$i以 2 為步長從 1 開始取值

警告:當存在帶有以下內容的文件時,這會嚴重破壞空白……我現在沒有更好的主意。

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

腳本現在可以變成單行...但我將透過添加 ie 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(也列出隱藏的目錄/文件,但省略和.)來做到這一點而且當然。對於,需要使其同時處理文件(包括隱藏文件)和目錄,而不僅僅是目錄,並停止對子目錄進行操作(就像's )..--all--color=alwaysdu--all--max-depth=1dufind-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-readabledu

答案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

相關內容