I want a shell script that keep all file with time-stamp of the same month as the current time + the latest file before that, and delete the rest of the files in the directory.

All filename stored in the directory are structured as name$timestamp.extension where

timestamp=`date "+%Y%m%d-%H%M%S"`

So, this means that if there is the following file in the directory:


The remaining file in the directory after the execution of this code will be:


PS. Extremely new to shell. Would love to not only have a working code, but also to learn. So, if you would be so kind, please explain the code as well. Thank you!

  • Can we rely on the mtime of the files and not just the filenames? – jayhendren Dec 14 '16 at 23:14
  • @jayhendren I wish I could use this: find filename -mtime +31 -type f -delete But, there are months that are 28, 30, 31 days as well. So, this method would not be inclusive enough keep "all files of the same month as the current time" + "the latest file before that". – Perth Dec 14 '16 at 23:22
  • that's ok, i was just wondering if the mtime is safe to key off of or if you can only use the name of the file to determine which ones to delete. – jayhendren Dec 14 '16 at 23:31
  • @jayhendren I see what you mean. mtime is safe. – Perth Dec 14 '16 at 23:57
  • just a off-topic hint: you might want to use 'backintime' as backup program which does what you require with default unix tools and data deduplication of your backups – Jaleks Dec 15 '16 at 0:24

With zsh you could do something like

# get current date (YYMM) in a variable 
crd=$(date "+%y%m")
# use a function to extract the 13 chars that make up the timestamp
dtts() REPLY=${${REPLY%%.*}: -13}
# sort file names by the timestamp in descending order, exclude the ones with the
# same YYMM as the current date and set the remaining file names as arguments
set -- *(.O+dtts^e_'[[ "${${REPLY%%.*}: -13:4}" == "$crd" ]]'_)
# remove the first item from the list (i.e. the last one before current month)
# print the remaining file names
print -rl -- "$@"

This uses parameter expansion and glob qualifiers:
it first selects regular files (.) sorts in descending order (O) by the timestamp using the dtts function, then the negated estring ^e_'[[ "${${REPLY%%.*}: -13:4}" == "$crd" ]]'_ deselects files if the timestamp matches current year and month (i.e. if the expression inside quotes returns true); shift then removes the first item from the list (since the names were sorted in descending order that would be the latest timestamp before current month)
Replace print -rl with rm if you're happy with the result.

  • zsh code was run on terminal platform. The function to extract 13 chars has an unexpected token - precisely at : -13 – Perth Dec 16 '16 at 16:44
  • @Perth - my post is pretty clear... it says with zsh. What you did was to open a terminal and simply run the code (and your shell is bash not zsh) hence the error bash: syntax error near unexpected token 'REPLY=${${REPLY%%.*}: -13}' – don_crissti Dec 16 '16 at 17:45
  • I see. So, bash and zsh cannot work together -Thanks for the clarification. – Perth Dec 16 '16 at 18:32
  • @Perth - no, your either run one or the other. Just install zsh (if not already installed on your system) and then open a terminal and execute zsh and then my code... – don_crissti Dec 16 '16 at 18:34

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.