4

If I run the command du -ah | sort -nr is it possible to make it show which line in the output is a file and which folder? Something like the command ls -l shows which is file and folder with d and - in front.

3
  • 1
    I seem not to understand what you try to achieve, the output show both the disk usage of a folder and of each included file. Is this really what you intended? Maybe the --max-depth=N or -hS options are a start?
    – hasgarion
    Dec 31, 2016 at 9:59
  • @hasgarion du command doesn't colorize it's output and doesn't append leading slash to a directory, so it's difficult to distinguish which one is file and which one is a folder in the output. That's what OP is asking about Dec 31, 2016 at 10:11
  • Hi , there. I've posted an answer. I think the last approach with find command would be ideal for what you want. Please let me know if that works well for you. Dec 31, 2016 at 10:24

2 Answers 2

8

It is sort of possible, but not without aid of another command. Specifically, here we're using GNU awk ( that's important, so check your awk version )

$ du -ah | sort -nr | awk '{usage=$1; $1="";cmd="file "$0;cmd |& getline type;print usage,type ;close(cmd)}'             
24K .: directory
4.0K ./testdir: directory
4.0K ./out.txt: ASCII text
4.0K ./3.txt: ASCII text
4.0K ./2.txt: ASCII text
4.0K ./1.txt: ASCII text

Of course this approach is slightly flawed since it seems to fail with filenames that contain spaces (still working on improving it )

As alternative, we can also use find command to find all the files and run file and du commands to do our bidding via -exec flag, but that looks slightly ugly (see the edit history). We could, however, use find's -printf flag to print filetype with %y format for much prettier output.

$ find -mindepth 1 -printf "%y\t" -exec  du "{}" \;  | sort -rn                                       
f   4   ./out.txt
f   4   ./3.txt
f   4   ./2.txt
f   4   ./1.txt
f   0   ./with space.txt
d   4   ./testdir

Obviously here f is for regular file and d is for directory. See find's manual for more info on flags and filetype letters

6

As Serg says, du can't do this by itself. To process filenames safely, the best way is to separate them with the ASCII nul character (\0), and du can do that. So, using that, along with sort and xargs' ability to handle null-delimited input:

du -0ah |
  sort -zh |
  xargs -0 sh -c 'for i; do s=${i%%[[:space:]]*};f=${i#*[[:space:]]}; echo "$s" "$(ls --color -dF "$f")"; done' _

The -0, -z and -0 options tell du, sort and xargs to use ASCII nul as the separator.

Then, s=${i%[[:space:]]*} to get the start of the line until whitespace (which is the size), and f=${i#*[[:space:]]} to get everything else (the filename). Then we get ls to print the filename with decoration.

Example:

$ du -0ah Screenshots | sort -zh | xargs -0 sh -c 'for i; do s=${i%%[[:space:]]*};f=${i#*[[:space:]]}; echo "$s" "$(ls --color -dF "$f")"; done' _
512 Screenshots/desktop.ini*
264K Screenshots/Screenshot (1).png*
269K Screenshots/

Because I used ls --color, I also get nice colour output:

enter image description here

2
  • 1
    How about this instead? du -0ah . | sort -zh | while read -r -d '' size file; do printf '%s %s\n' "$size" "$(ls --color -dF -- "$file")"; done. You don't really need an extra xargs and sh. Dec 31, 2016 at 12:10
  • @gniourf_gniourf of course. while is underappreciated. 😁 I just default to xargs.
    – muru
    Dec 31, 2016 at 12:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .