7

Oracle Linux 5.10
BASH shell

[oracle@src01]$ getconf ARG_MAX
131072

[oracle@srv01]$ ls -1 | wc -l
40496

#!/bin/bash
#
# delete files in /imr_report_repo that are older than 15-days
find /imr_report_repo/* -maxdepth 0 -type f -mtime +15 |
while read file
do
    rm -f $file 
done

/usr/bin/find: Argument list too long

If I'm reading this right the maximum arguments allowed is 131,072 and I only have 40,496 files in this directory. I haven't checked, but I'm probably trying to delete 40,000 files (over 2-weeks old).

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Stringer
  • 339
  • 3
  • 5
  • 12
  • We're talking about the maximum _length_ of the command line argument (128K in this case)... Remove the `*` (why would you need that ?) and retry. I'm not sure why you need the `while..read` loop either... – don_crissti Mar 02 '16 at 20:53
  • @don_crissti is right. in other words: `find /imr_report_repo/ -maxdepth 1 -type f -mtime +15 -exec rm {} +`. or if you're trying to delete files in immediate sub-directories of `/imr_report_repo/` (but not /imr_report_repo itself) then use `find /imr_report_repo/*/ -maxdepth 0 -type f -mtime +15 -exec rm {} +` - note the trailing `/` (but note also that this is also subject to ARG_MAX limit of 128Kbytes). – cas Mar 02 '16 at 21:02
  • @cas Thanks! Please consider moving your comment to an answer. – Stringer Mar 02 '16 at 21:28
  • Is the `-delete` option not available in your `find`? – FelixJN Mar 02 '16 at 21:48
  • @Fiximan -delete is available, but we have other systems where it is not available. Keeping portability in mind – Stringer Mar 02 '16 at 21:56
  • In that case you'll have to remove the `maxdepth` because it's only available where/when `delete` is available too... – don_crissti Mar 02 '16 at 21:59

3 Answers3

19

I think this has been answered here:

https://arstechnica.com/civis/viewtopic.php?t=1136262

The shell is doing a file expansion of /imr_report_repo/* , which causes the problem. I had a similar issue which I fixed by changing the find command from

find /imr_report_repo/* -maxdepth 0 -type f -mtime +15 

to

find /imr_report_repo/ -name "*" -maxdepth 0 -type f -mtime +15 

The quotes keep the shell from expanding the wildcard and then find can use it as a regular expression. It also helps if you need to search for a large number of files that match a specific criteria (like "*.foo").

John H
  • 291
  • 2
  • 5
1

The maximum command line length is the total size in bytes, not the number of arguments. 40k files with names of the form /imr_report_repo/* means a minimum of about 800kB, probably more. That's over the limit.

The obvious solution is to make find do the recursion for you. Go from depth 1 to depth 1 instead of depth 0 to depth 0.

find /imr_report_repo/ -mindepth 1 -maxdepth 1 -type f -mtime +15 -delete

Unlike the original, this includes files whose name begins with . (dot files). If you don't want that, exclude them:

find /imr_report_repo/ -mindepth 1 -maxdepth 1 -name '.*' -prune -o -type f -mtime +15 -delete

Most find implementations that have -maxdepth also have -delete. If yours doesn't, don't just pipe the result into while read: it's somewhat slow and breaks on file names containing newlines (and backslashes and trailing whitespace because you used read where you should have used IFS= read -r). Use -exec, that's what it's for.

find /imr_report_repo/ -mindepth 1 -maxdepth 1 -type f -mtime +15 -exec rm -f {} +
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
0

Try: find /imr_report_repo/ -maxdepth 1 -type f -mtime +15 -exec rm {} + or, as suggested by @Fiximan, find /imr_report_repo/ -maxdepth 1 -type f -mtime +15 -delete

If you're trying to delete files in immediate sub-directories of /imr_report_repo/ (but not /imr_report_repo itself) then use find /imr_report_repo/*/ -maxdepth 0 -type f -mtime +15 -exec rm {} + (or ... -delete) - note the trailing /

note also that this is also subject to ARG_MAX limit of 128Kbytes.

cas
  • 1
  • 7
  • 119
  • 185