tags:

views:

34

answers:

3

I'm using bash.

Suppose I have a log file directory /var/myprogram/logs/.

Under this directory I have many sub-directories and sub-sub-directories that include different types of log files from my program.

I'd like to find the three newest files (modified most recently), whose name starts with 2010, under /var/myprogram/logs/, regardless of sub-directory and copy them to my home directory.

Here's what I would do manually
1. Go through each directory and do ls -lt 2010* to see which files starting with 2010 are modified most recently.
2. Once I go through all directories, I'd know which three files are the newest. So I copy them manually to my home directory.

This is pretty tedious, so I wondered if maybe I could somehow pipe some commands together to do this in one step, preferably without using shell scripts?

I've been looking into find, ls, head, and awk that I might be able to use but haven't figured the right way to glue them together.

Let me know if I need to clarify. Thanks.

A: 

Here's how you can do it:

 find -type f -name '2010*' -printf "%C@\t%P\n" |sort -r -k1,1 |head -3 |cut -f 2-

This outputs a list of files prefixed by their last change time, sorts them based on that value, takes the top 3 and removes the timestamp.

Hasturkun
I really like this solution. You didn't even use a FOR loop. Thanks.
Russell
A: 

My "shortest" answer after quickly hacking it up.

for file in $(find . -iname *.php -mtime 1 | xargs ls -l | awk '{ print $6" "$7" "$8" "$9 }' | sort | sed -n '1,3p' | awk '{ print $4 }'); do cp $file ../; done

The main command stored in $() does the following:

  1. Find all files recursively in current directory matching (case insensitive) the name *.php and having been modified in the last 24 hours.

  2. Pipe to ls -l, required to be able to sort by modification date, so we can have the first three

  3. Extract the modification date and file name/path with awk

  4. Sort these files based on datetime

  5. With sed print only the first 3 files

  6. With awk print only their name/path

  7. Used in a for loop and as action copy them to the desired location.

Or use @Hasturkun's variant, which popped as a response while I was editing this post :)

mhitza
A: 

Your answers feel very complicated, how about

for FILE in find . -type d; do ls -t -1 -F $FILE | grep -v "/" | head -n3 | xargs -I{} mv {} ..; done;

or laid out nicely

  for FILE in `find . -type d`; 
  do
      ls -t -1 -F $FILE | grep -v "/" | grep "^2010" | head -n3 | xargs -I{} mv {} ~;
  done;
Henry Slater