4

So I have this command line that works.

find . -type f |xargs ls -lS |head -20

The thing is I only want the output to be the file size and the name. I tried:

find . -type f -printf '%s %p\n' |xargs ls -lS |head -20

but this gives me a bunch of 'cannot access [inode], no such file or directory' errors.

My goal is to print the biggest 20 files in the directory, not using ls.

  • 4
    Just do `find . -type f -printf '%s %p\n'` and drop the `xargs`. – Kenney Feb 03 '16 at 20:26
  • That does work, but I'm looking to output the biggest 20 files, so I need those xargs and the head. –  Feb 03 '16 at 20:32

5 Answers5

3

An answer without ls involved:

find . -type f -printf '%k %p\n' |sort -n |tail -n 20

This gives each file, listed with the size (in kB), a space, then the file name, sorted numerically, and then you get the last 20 items (the 20 largest).

Your problem was in piping to ls.

If you've got a really big directory structure, sort will fall over. You'd have to use custom code that stores only the largest 20 items.

Adam Katz
  • 14,455
  • 5
  • 68
  • 83
2

Use following commmand to get size of the fiule in linux.

du -h <<FileName>>

Or

du -h <<FilePath>>
Mukrram Rahman
  • 426
  • 2
  • 14
2

In the question, you state:

My goal is to print the biggest 20 files in the directory, not using ls.

This implies that an acceptable solution should not use ls.

Another issue is the use of xargs. A construction like find . -type f | xargs ls will not work with subdirectory or file names containing white space, since it will split the string from find before giving it to ls. You can protect the string or work around this using null terminated strings, such as find . -type f -print0 | xargs -0 ls. In general, there are security considerations for using xargs. Rather than verifying if your xargs construction is safe, it's easier to avoid using it altogether (especially if you don't need it).

Try printing the 20 biggest files without ls and without xargs:

    find . -type f -printf '%s %p\n' | sort -rn | head -20
e0k
  • 6,961
  • 2
  • 23
  • 30
1

find . -type f |xargs ls -lS |head -20 | awk '{print $9, $5}'

Since the output of ls is columnar, just print the proper columns and you're done.

Anton Drukh
  • 873
  • 7
  • 12
  • welcome to the wonderful world of `awk` - next stop is averaging values with `cat some.csv | awk '{s+=$4} END {print s/NR}'` – Anton Drukh Feb 03 '16 at 20:58
  • 2
    What happens if a file name contains a space? – e0k Feb 03 '16 at 23:31
  • 2
    @e0k the code in this answer is completely broken… (spaces or quotes would break it badly). It seems we're having new waves of very bad answers… – gniourf_gniourf Feb 03 '16 at 23:32
  • Thanks for pointing out the limitations here! Indeed a 80%/20% type of answer, not to be used without understanding the limitations of `awk` – Anton Drukh Feb 05 '16 at 10:04
  • This only works when the output of find is small enough for xargs to place into a single call to ls. Otherwise, it'll split the results into multiple runs of ls and each of those clumps will be sorted, but you'll only see the 20 largest of the _first_ ls called by xargs. – Adam Katz Apr 28 '17 at 20:17
0

xargs takes each line of output from the previous command and basically slaps at the end of its arguments, so your find is printing something like

123 ./somefile.txt 

which xargs turns into

ls -lS 123 ./somefile.txt

unless you actually have a file named 123 in that directory, you get your "cannot access" error:

marc@panic:~$ touch foo
marc@panic:~$ ls -lS file_that_does_not_exist foo
ls: cannot access file_that_does_not_exist: No such file or directory
-rw-rw-r-- 1 marc marc 0 Feb  3 14:26 foo
Marc B
  • 356,200
  • 43
  • 426
  • 500