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

Stringer
  • 349
  • 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

20

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
  • 301
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 {} +
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
  • 78,579