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_COLORS )

答え1

このzshスクリプトは を解析します$LS_COLORSstatすべてのファイルに対して 1 回だけ呼び出す必要があるため、すべてのファイルに対して呼び出す下部のソリューションよりもはるかに高速ですls。また、スペースを含むファイルも正しく処理します。(\nまたは、\tまだないファイル名に使用できる)

ただし、実装は完全ではありません。ファイル モード文字列の最初の文字 (lrwxrwxrwxシンボリック リンクなど) またはファイル拡張子によって識別できるさまざまなファイル タイプの色のみを含めました。つまり、誰でも書き込み可能な権限、suid、またはスティッキー ビットは特別な色付けは行われません。これらを含めることも簡単なはずです。

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

これは私の古いスクリプトで、 用です。ファイルごとに 1 つのコマンドが発行される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ループは配列を参照し、$i1から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=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/null制限されたディレクトリでpermission 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ディスク使用状況、ディレクトリの色、上記両方の出力の組み合わせ、数値の逆順ソート、最大のファイル/ディレクトリの出力、最初の列 (サイズ) と 3 番目の列 (ファイル/色付きディレクトリ名) のみの出力-c:grand total -k: 1Kb blocks -s: entry
ls
paste
sort -nr
head
awk

関連情報