This is the greatest Linux command ever! Definitely my favorite.
What it does is look (find) for files that end in .html uses the printf option to format the 'find' output, then passes it to grep for searching for a certain date, then awk for printing a certain field, and finally xargs for executing a certain command.
Let's break it down...
The printf part within the find command has the format '%CD\t%p\n'.
%Cx = File's last status change time in the format specified by x. x=D. D=date in the format mm/dd/yy
\t = Horizontal tab
%p = file's name
\n = newline
So basically it outputs the file's last status change followed by a horizontal tab, then the filename, and then a new line. But before it outputs it, it sends it to 'grep' which searches the output and only outputs lines with "03/10/09".
Example so far: (minus the awk, xargs and mv commands)
find ./ -name \*.html -printf '%CD\t%p\n' | grep "03/10/09"
Outputs this: (notice the tab to separate the 2 fields)
03/10/09 ./2005/05/index.html
03/10/09 ./2005/03/index.html
03/10/09 ./2005/04/index.html
03/10/09 ./linked-in.html
03/10/09 ./consumer-electronics/samsung-bribery-news.html
03/10/09 ./technology/iptv/index.html
Now send this output into the awk command (awk '{print $2}') which parses it and pulls out the 2nd column/field (hence the tab character), which is the filename, including the path.
Here's the output you now have after adding awk '{print $2}' in:
./2005/05/index.html
./2005/03/index.html
./2005/04/index.html
./linked-in.html
./consumer-electronics/samsung-bribery-news.html
./technology/iptv/index.html
Next, send this output of "exact path + filename" to xargs for execution in the Linux shell.
The "xargs -t -i mv {} temp/" part basically takes the input from the previous commands (files named .html modified on 3/10/09) and moves (mv) them to the temp/ folder.
The xargs command can do anything. So instead of moving the files, I could delete them, run chmod on them, or something else.
It took me awhile to write this command. I've used various methods of finding files on Linux servers over the years, but this one is one of the most powerful.
Definitely a command you should have in your Linux arsenal!
p.s. Here's another tip. If you want to search ALL files (not just .html) then use the following command. Notice the \* and not * for the search. That part got me since I didn't think the * (wildcard) had to be backslashed. Usually when you backslash a character that means you want the 'literal' character specified after the \ (backslash) character. I didn't want filenames with a '*' in it. I wanted the wildcard. That threw me for a minute before I figured it out. Anyway, here's the command:
find ./ -name \*.html -printf '%CD\t%p\n' | grep "03/10/08" | awk '{print $2}' | xargs -t -i mv {} temp/
What it does is look (find) for files that end in .html uses the printf option to format the 'find' output, then passes it to grep for searching for a certain date, then awk for printing a certain field, and finally xargs for executing a certain command.Let's break it down...
The printf part within the find command has the format '%CD\t%p\n'.
%Cx = File's last status change time in the format specified by x. x=D. D=date in the format mm/dd/yy
\t = Horizontal tab
%p = file's name
\n = newline
So basically it outputs the file's last status change followed by a horizontal tab, then the filename, and then a new line. But before it outputs it, it sends it to 'grep' which searches the output and only outputs lines with "03/10/09".
Example so far: (minus the awk, xargs and mv commands)
find ./ -name \*.html -printf '%CD\t%p\n' | grep "03/10/09"
Outputs this: (notice the tab to separate the 2 fields)
03/10/09 ./2005/05/index.html
03/10/09 ./2005/03/index.html
03/10/09 ./2005/04/index.html
03/10/09 ./linked-in.html
03/10/09 ./consumer-electronics/samsung-bribery-news.html
03/10/09 ./technology/iptv/index.html
Now send this output into the awk command (awk '{print $2}') which parses it and pulls out the 2nd column/field (hence the tab character), which is the filename, including the path.
Here's the output you now have after adding awk '{print $2}' in:
./2005/05/index.html
./2005/03/index.html
./2005/04/index.html
./linked-in.html
./consumer-electronics/samsung-bribery-news.html
./technology/iptv/index.html
Next, send this output of "exact path + filename" to xargs for execution in the Linux shell.
The "xargs -t -i mv {} temp/" part basically takes the input from the previous commands (files named .html modified on 3/10/09) and moves (mv) them to the temp/ folder.
The xargs command can do anything. So instead of moving the files, I could delete them, run chmod on them, or something else.
It took me awhile to write this command. I've used various methods of finding files on Linux servers over the years, but this one is one of the most powerful.
Definitely a command you should have in your Linux arsenal!
p.s. Here's another tip. If you want to search ALL files (not just .html) then use the following command. Notice the \* and not * for the search. That part got me since I didn't think the * (wildcard) had to be backslashed. Usually when you backslash a character that means you want the 'literal' character specified after the \ (backslash) character. I didn't want filenames with a '*' in it. I wanted the wildcard. That threw me for a minute before I figured it out. Anyway, here's the command:
find ./ -name \* -printf '%CD\t%p\n' | grep "03/10/08" | awk '{print $2}' | xargs -t -i mv {} temp/


Technorati
Del.icio.us
Slashdot
Digg
twitter
Wouldn't a "find ./ -name \*.html -mtime ???? -exec mv {} /temp/ \;" perform the same function using a single command? (Instead of launching an additional 2 text manipulation programs and a second shell environment.)
The time you're placing in the formated output to latter grep and manipulate is something find can filter on internally.
Also, a "find ./ -mtime ???? -exec mv {} /temp/" would work on all files, just remove the "-name" filter and it will find everything...
I'd suggest looking at the manual or info pages for find, it can filter results on access, modified or filesystem status change (most often file create), file and file system type as well as many other things. Also, it can format the output in many ways, especially the "-exec" flag, it can run anything...
(Either "man find" or "info find" on most distros.)
That's one more function than you need.
find ./ -name \*.html -printf '%CD\t%p\n' | awk '$1 ~ /03\/10\/08/ {print $2}' | xargs -t -i mv {} temp/
This will do the same without needing a call to grep. Awk lets you search through lines for a regex then take an action based on the match succeeding. The regex in this case needs the '/' escaped so it ends up looking like a picket-fence (\/\/\/\).
I like a challenge :-)
would this do the same?
find -iname "*.html" -daystart -mtime 2 -exec mv "{}" temp/ \;
john
John >> would this do the same? find -iname "*.html" -daystart -mtime 2 -exec mv "{}" temp/ \; john (1 reply)
Yes it would. But yours requires the user to calculate the date (-mtime 2). What if it was months or years ago? You'd have to count the number of days backwards and manually calculate the mtime. That's a pain. Mine allows you to use a nice clean date format.
Clay - good point about using awk and eliminating grep. I'm so used to using grep for string searches.
Tom - you really scare me! I remember back in the mid-80's sitting in the darkened labs trying to work out complex one-line shell scripts (just for fun). Some things just never die!
Nice blog.
The asterisk is being interpreted by the shell. Put it in quotes. The man for 'find' says, "Please note that you should quote patterns as a matter of course, otherwise the shell will expand any wildcard characters in them."
The shell does globbing. Additional info: 'man 7 glob'
GNU/Linux Command-Line Tools Summary
http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/wildcards.html