Quote:
Originally Posted by sr_sanjeev
Hi
Either you can write a small script or use like
ls -alrt | grep 2008 | rm -rf *
but before doing that , please ensure that first 2 commands are serving your purpose or not?
|
Quote:
Originally Posted by Penn
OK......Im going to move the mails to another directory first before i remove it. When i use the following:
"ls -alrt | grep 2008 | mv -rf * /directory"
then i recieve
"Argument list too long"
|
Do yourself a favour and do not use this syntax. However well-intentioned we may presume this suggestion was, there are a few problems:
sr_sanjeev, while "ls -alrt" will certainly provide a long (-l) listing of all (-a) sorted by reversed (-r) time (-t), this in no way actually filters based on any dates at all. Using the "-rt" certainly helps you the human get a listing that's easier to see file modification dates, but it doesn't help the computer and provides no help for the subsequent "grep" or "mv"/"rm" commands.
Penn, you were wise to change the originally-suggested "rm" to a "mv", but the "-r" flag doesn't make sense for a "mv" (any directory moved will automatically "take" its files with it). Grepping 2008 out of the output will give you all the lines that have 2008 in them, which means that you could conceivably get files before or after you intend. This also ignores the fact that most copies of "ls" will only show the year for long listings over a certain age, so most listings will have date strings like "Mar 17", "Aug 14", or "Oct 2" that don't include the 2008 this command would pick up on.
In addition, even if you did grep a long listing, grep is providing the _whole_ line, including the file permissions, owner, etc., in addition to the filename.
ledow, you're on the right track as far as passing filenames to "rm" via a pipe: you would need to use "xargs" to pass multiple options from the ls/grep output streams to the rm command, but you'd also need to remove the "*" (details below).
Unfortunately, if you passed the grep output to "xargs rm" you'd be telling "rm" to not only delete the filenames that grep returns, but also any filenames that happened to match anything else on those returned lines, including the username that owns them, the directory permissions, the parts of the datestamps, and anything else on the line separated by whitespace, really.
Finally, and most importantly, the wildcard "*" is expanded by the shell _before_ any of the commands are executed, which means that "*" is still the wildcard for all the files in your current directory, regardless of what other commands you pass to "rm", either directly or via a pipe. Adding "rm -rf *" to _anything_ means you're trying to delete _all_ the files and directories in your current directory (wherever that is), regardless of any flags, arguments, or piped input. If you want an illustration of what you're trying to delete, add an "echo" in front of the original "rm" (instead of the "mv" you put), and you'll see what you were telling it to delete.
If you want to see what I mean, just do this (please KEEP the echos where I put them to ensure you're not actually deleting anything accidentally):
Code:
ls -l | grep 2008 | echo rm *
or this:
Code:
ls -l | grep 2008 | xargs echo rm *
Here's an illustration in a "safe" directory for testing purposes:
Code:
% mkdir tmp_never_pipe_to_rm-rf-star
% cd tmp_never_pipe_to_rm-rf-star
% touch all in zdirectory
% touch -r ../.bashrc files
% touch -r ../.gnome here
% touch -r ../.xscreensaver this
% ls -l
total 0
-rw-r--r-- 1 bmsnook bmsnook 0 Oct 21 11:59 all
-rw-r--r-- 1 bmsnook bmsnook 0 May 23 12:32 files
-rw-r--r-- 1 bmsnook bmsnook 0 Jun 29 2007 here
-rw-r--r-- 1 bmsnook bmsnook 0 Oct 21 11:59 in
-rw-r--r-- 1 bmsnook bmsnook 0 Mar 21 2007 this
-rw-r--r-- 1 bmsnook bmsnook 0 Oct 21 11:59 zdirectory
%
Now look what happens when we pipe a grep of this listing to "rm *":
Code:
% ls -l | grep 2007 | echo rm *
rm all files here in this zdirectory
Now, note that not only did it not take any filtering based on our grep, but it just plain wants to delete everything. You'd need "xargs", but you'd also want to remove the "*". Compare with and without the wildcard:
Code:
## With the wildcard
% ls -l | grep 2007 | xargs echo rm *
rm all files here in this zdirectory -rw-r--r-- 1 bmsnook bmsnook 0 Jun 29 2007 here -rw-r--r-- 1 bmsnook bmsnook 0 Mar 21 2007 this
## Without the wildcard
% ls -l | grep 2007 | xargs echo rm
rm -rw-r--r-- 1 bmsnook bmsnook 0 Jun 29 2007 here -rw-r--r-- 1 bmsnook bmsnook 0 Mar 21 2007 this
Obviously, grep alone isn't what we want. The simplest way to get the filename if you're doing a long listing-based filter is to use awk and print "$NF" (the field in the position of the number of fields in the line, which is the last field):
Code:
% ls -l | awk '/2007/{print $NF}' | xargs echo rm
rm here this
That's closer, but you're still deleting everything based on a year, without any granularity for month or day. Here is a straightforward way to get the granularity you want with the "date" and "find" commands built into your system. Please refer to my response in Post#5 ('use "date --date" and shell math to pass file ages to "find"') for a full-blown explanation of all the "whys" about the date stuff. Here are the commands to conduct a full-on test on your own system without deleting your own stuff.
Code:
mkdir -p tmp_find_date_delete/tmp_stuff_to_delete
cd tmp_find_date_delete/tmp_stuff_to_delete
touch -t 200801010001 zfilebegin01
for month in {01..10}; do for day in 01 15 28; do \
for time in 0030 1130 1330 1830 2330; do \
touch -t 2008${month}${day}${time} zfiledelete${month}${day}${time}; \
done; done; done
touch -t 200808310001 zfileend0001
touch -t 200808312359 zfileend2359
touch -t 200712310001 zfilekeep.200712310001
touch -t 200712311130 zfilekeep.200712311130
touch -t 200712311330 zfilekeep.200712311330
touch -t 200712312359 zfilekeep.20071231
touch -t 200809010001 zfilekeep.20080901
touch -t 200809011130 zfilekeep.20081130
touch -t 200809011330 zfilekeep.20081330
touch -t 200809012359 zfilekeep.20082359
DOY_BEGIN=`date --date 01/01/2008 '+%j'`
DOY_END=`date --date 08/31/2008 '+%j'`
DOY_TODAY=`date '+%j'`
let AGE_OLDEST=${DOY_TODAY}-${DOY_BEGIN}
let AGE_YOUNGEST=${DOY_TODAY}-${DOY_END}
echo ${AGE_OLDEST}
echo ${AGE_YOUNGEST}
mkdir ../tmp_move-remove_testdir
find . -mtime -${AGE_OLDEST} -mtime +${AGE_YOUNGEST} -ls
find . -mtime -${AGE_OLDEST} -mtime +${AGE_YOUNGEST} -ls -exec mv {} ../tmp_move-remove_testdir/ \;
Depending on what you find, you may need to play around with options like this:
Code:
let AGE_OLDEST=${DOY_TODAY}-${DOY_BEGIN}+1
let AGE_YOUNGEST=${DOY_TODAY}-${DOY_END}-1
and you may need to move files back before deleting the rest to avoid collateral damage, based on file modification times and when you run the script, which is another excellent reason to use mv instead of rm initially (i.e., I end up either missing some files from 2008-01-01 or inadvertently getting some files from 2007-12-31, depending on which I use, so I need to move some back or away).