I want to find some files based on some pattern in their paths and then I want to keep only the 3 latest files of that pattern and the others I want to delete.

  • Can the pattern occur anywhere in the "path", or does it have to occur in the file name? – Jeff Schaller May 18 '18 at 11:14
  • what is the sort criteria if you say the 3 latest? Is latest = newest? If yes, based on last modification, creation or access? – pLumo May 18 '18 at 11:41

With zsh:

echo rm -f ./**/*pattern*(.Dom[4,-1])
  • **/ any level of subdirectories
  • (...) glob qualifiers to qualify the match on other criteria:
  • .: regular files only
  • D: include dot-files (hidden files) and look into hidden dirs
  • om: order by modification time (newest to oldest)
  • [4,-1]: from 4th to last (so skips the first 3).

(remove echo to actually do it)

For an equivalent using any POSIX shell and GNU utilities:

(export LC_ALL=C
find . -name '*pattern*' -type f -printf '%T@/%p\0' |
  sort -zrn |
  tail -zn +4 |
  cut -zd/ -f2- |
  xargs -r0 echo rm -f)

(remove echo to actually do it)

With older versions of GNU utilities, you may need:

(export LC_ALL=C
find . -name '*pattern*' -type f -printf '%T@/%p\0' |
  tr '\n\0' '\0\n' |
  sort -rn |
  tail -n +4 |
  cut -d/ -f2- |
  tr '\n\0' '\0\n' |
  xargs -r0 echo rm -f)

well, sorting requires a logic around it but so far:

# Create an array with the files you want to target
FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever")
# Get the total size of the array 
# Detract 3 from total size to create a threshold
# Declare a counter at 0
# iterate file by file in the array
for FILE in "${FILES[@]}"
   # make sure that you do this until 3 files are left
   while [ ${counter} -le ${stopat} ]
      rm -v ${FILE}

when using -name you can use extended expressions, e.g. *.sh or hello*.sh or *hello.sh etc.

Please note the above command will delete all files but 3, use the command sort to sort the files as desired (either using size, creation or modification date) here:

FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever")

  • It would be nice if you actually showed how to use the sort command to sort a list of files by a file attribute like modification date/time. – G-Man Says 'Reinstate Monica' Dec 30 '19 at 22:56
  • you could actually exec ls -la and then pipe it with sort, FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever" -exec ls -al {} \; | sort -k 5 -n) 1. you execute ls -la 2. you pipe the output to sort and then -k 5 to select the fifth column and -n for numeric sort. This will return smaller to bigger sort. If you want it bigger to smaller, then add a -r – Kramer Jan 2 at 13:43
  • for mod-date, you would change it as this: FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever" -print0 | xargs -0 /bin/ls -ltr – Kramer Jan 2 at 13:56
  • and to clean the array and leave just the paths to files awk '{print $9}' for the 9th column file-size: FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever" -exec ls -al {} \; | sort -k 5 -n) | awk '{print $9}' mod-date: FILES=$(find ${PATH_TO_FOLDER} -type f -name "whatever.whatever" -print0 | xargs -0 /bin/ls -ltr | awk '{print $9}' – Kramer Jan 2 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.