LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-15-2018, 12:03 PM   #1
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Rep: Reputation: 103Reputation: 103
delete 1 month-old files except when if only a number of files are left


I'm doing a daily backup for a mysql database and once a month I delete all files that are older than a month. So there are about 30-31 files per month, and double that, the moment I run the clean-up command.
Code:
if [ $(ls /path/to/dir/mysql* | wc -l) -lt 31 ]; then 
    echo "There are too few files. Not proceeding." && exit 2
else
    find /path/to/dir/ -name "mysql*" -mtime +30 -exec rm rf {} \;
fi
Is there a better, cleaner and safer way to do this than using wc to count the backup files?

Thanks
 
Old 05-15-2018, 12:21 PM   #2
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,883
Blog Entries: 13

Rep: Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931
I would say that solution for the very custom decision you've reached is fine. However, I feel that older files no matter how many of them are either worthless or they are not depending upon the age. Therefore I might lend towards solely the line in your else clause and leave it at that. I'm sure you have your reasons for wishing to retain some small number of files.
 
Old 05-15-2018, 12:37 PM   #3
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,775

Rep: Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933
Are you creating daily backups? There are many ways to delete old files. How do you run your script? How are your files named?

One method would be to label your backup files as date_mysql_backup where the date could be the current month i.e. 05_xyx_mysql_backup. Create a cron job to delete your scripts on the 1st day of the month.

Code:
MM HH 1 * * /path/to/my/script

#!/bin/bash
old_files=$(date +'%m' -d 'last month')
rm old_files*
Do you care about keeping just a months worth of backups or an entire month as defined by the days of the month (1-31). If just the past 31 days of backups regardless of the exact day then run a cron script everyday.
Code:
MM HH * * * find /path/to/dir/ -name "mysql*" -mtime +31 -exec rm rf {} \;
Most do not understand that with ASCII sorting labeling files using the date-name (YYYYMMDD-name) is easier to script and automatically sorts versus name-MMDDYYYY.
 
Old 05-15-2018, 12:43 PM   #4
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,883
Blog Entries: 13

Rep: Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931
I supposed a real other way to contend with this is to use logrotate and specify the age and number of files limits for rotation, along with the number of backups intended to be kept. Plus you can zip the backups so that the results will be smaller, assuming they are text files in the first place. Logrotate is not just for system logs, it also does not have to be for files ending in .log, it can be for any directory, any file extension, or even no extension, it is that flexible.
 
Old 05-15-2018, 12:45 PM   #5
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,775

Rep: Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933Reputation: 5933
logrotate would be the obvious answer....
 
Old 05-15-2018, 02:20 PM   #6
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,821

Rep: Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212
Quote:
Originally Posted by vincix View Post
I'm doing a daily backup for a mysql database and once a month I delete all files that are older than a month. So there are about 30-31 files per month, and double that, the moment I run the clean-up command.
Code:
if [ $(ls /path/to/dir/mysql* | wc -l) -lt 31 ]; then 
    echo "There are too few files. Not proceeding." && exit 2
else
    find /path/to/dir/ -name "mysql*" -mtime +30 -exec rm rf {} \;
fi
Is there a better, cleaner and safer way to do this than using wc to count the backup files?

Thanks
You are deleting files and directories that are older than 30 days.
ls is okay, but a shell builtin is elegant+efficient
Code:
argcnt(){ echo $#; }
if [ $(argcnt /path/to/dir/mysql*) -lt 31 ]
then
    echo "There are too few files. Not proceeding." && exit 2
else
    find /path/to/dir/ -maxdepth 1 -type f -name "mysql*" -mtime +30 -delete
fi
As was stated already, in most practical cases (one file per day is produced) the find statement is sufficient.
 
1 members found this post helpful.
Old 05-16-2018, 08:56 AM   #7
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
This is how I create my mysqldump backup files:
Code:
export mysqlpwd=mypassword
mysqldump -u root -p$mysqlpwd --single-transaction --routines --triggers --databases my_db > /mnt/backup_orange_nfs/mysql/my_db_$(date +%F.%H:%M:%S).sql
@michaelk So I guess my naming method is name-YYYYMMDD, which is neither. But your point is that, besides the format, the date should stand in front of the name.
So given this, the find command actually looks for my_db* (not mysql, as state initially - I simply showed how I did it in my first post, wasn't entirely accurate in this respect)

I'll have a look at logrotate. It seems logic to make use of a system which is already in place in linux. It's just that I don't have lots of experience with logrotate and sometimes I feel it's a little bit daunting, not sure why. It doesn't seem that hard to understand


@MadeInGermany
I don't understand exactly how your function works. How does the number of position parameters ($#) gives the number of files in this context exactly? Can you use $# to count the number of files without using a function, just for the sake of demonstration?
 
Old 05-16-2018, 12:58 PM   #8
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,821

Rep: Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212
The shell looks into the file system and expands /path/to/dir/mysql* to words.
The function is run with them as arguments. They are mapped to positional parameters within the function (these are indeed local to the function, not overwriting the positional parameters in the main script).

There might be a way to count words without using a function - but I don't know a good one.
 
Old 05-16-2018, 03:36 PM   #9
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
You can set positional parameters without affecting the script in the command substitution as it is executed in a subshell
Code:
if [ $(set -- /path/to/dir/mysql*; echo $#) -lt 31 ]; then...
 
Old 05-17-2018, 05:02 AM   #10
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
Please remind me, what does -- stand for in this context?
 
Old 05-17-2018, 05:07 AM   #11
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 7,343
Blog Entries: 3

Rep: Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754Reputation: 3754
Quote:
Originally Posted by vincix View Post
Please remind me, what does -- stand for in this context?
From the bash manual page, the function "set" under the section "shell builtin commands"
-- If no arguments follow this option, then the positional
parameters are unset. Otherwise, the positional parame‐
ters are set to the args, even if some of them begin
with a -.

See the manual about what + and - do for each parameter
 
Old 05-17-2018, 05:44 AM   #12
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,821

Rep: Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212Reputation: 1212
The -- option means it is the last option. In the case of
set -- $var
and $var being "-brave world" the set command should not see options -b -r -a -v -e

Here we know that the arguments start with / so we can omit the --
 
Old 05-17-2018, 08:29 AM   #13
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
I noticed the trick to use positional parameters to count elements in a directory using globing gives wrong result when a directory is empty

Because when globbing doesn't occur then bash uses the globing string as first parameter, so $# will contain 1...

Code:
> echo $(set /path/to/empty/dir/*; echo $#)
1

Maybe we can add a test like
Code:
echo $(set /path/to/empty/dir/*; [ "${1: -1}" = '*' ] && echo 0 || echo $#)
Or just use nullglob
Code:
shopt -s nullglob
echo $(set -- /path/to/empty/dir/*; echo $#)
here the -- that follows set is required because without it, set will output all env variables
Code:
help set
...
If no ARGs are given, all shell variables are printed.


I know wrong count result with empty directory is irrelevant in this application, but just wanted to point this

Last edited by keefaz; 05-17-2018 at 08:49 AM.
 
1 members found this post helpful.
Old 05-17-2018, 09:21 AM   #14
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
Well, even if it might not affect the script itself, it doesn't seem like something you can easily ignore. Perhaps the 'ls' solution might be cleaner.
 
Old 05-17-2018, 09:33 AM   #15
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
I found pipes with ls don't always end nicely (filenames with spaces...)
Globbing is cool, keeping in mind its default behaviour with non results
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] rsync [...] --delete - number of files not the same AdultFoundry Linux - Newbie 2 11-01-2016 03:01 AM
how to delete number of files packets Linux - Newbie 8 02-09-2015 07:46 PM
zero disk space left even if i delete files wakkana12 Slackware 13 09-07-2010 09:56 AM
Delete old update files left by Yast/YOU? asmirnov SUSE / openSUSE 1 02-27-2007 09:55 PM
delete files older then a month? Red Squirrel Linux - Software 1 10-05-2005 10:54 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:30 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration