unix command to find most recent directory created

23,636

Solution 1

This is the answer to the question I think you are asking.

When I deal with many directories that have date/time stamps in the name, I always take the approach that you have which is YYYYMMDD - the great thing about that is that the date order is then also the alphabetical order. In most shells (certainly in bash and I am 90% sure of the others), the '*' expansion is done alphabetically, and by default 'ls' return alphabetical order. Hence

    ls | head -1
    ls | tail -1

Give you the earliest and the latest dates in the directory.

This can be extended to only keep the last 5 entries etc.

Solution 2

lastdir=`ls -tr <parentdir> | tail -1`

I don't know how to make the backticks play nice with the commenting system here. Just replace those apostrophes with backticks.

Solution 3

The trouble with the ls based solutions is that they are not filtering just for directories. I think this:

cp `find . -mindepth 1 -maxdepth 1 -type d  -exec stat -c "%Y %n" {} \;  |sort -n -r |head -1 |awk '{print $2}'`/* /target-directory/.

might do the trick, though note that that will only copy files in the immediate directory. If you want a more general answer for copying anything below your newest directory over to a new directory I think you would be better off using rsync like:

rsync -av `find . -mindepth 1 -maxdepth 1 -type d  -exec stat -c "%Y %n" {} \;  |sort -n -r |head -1 |awk '{print $2}'`/ /target-directory/ 

but it depends a bit which behaviour you want. The explanation of the stuff in the backticks is:

  • . - the current directory (you may want to specify an absolute path here)
  • -mindepth/-maxdepth - restrict the find command only to the immediate children of the current directory
  • -type d - only directories
  • -exec stat .. - outputs the modified time and the name of the directory from find
  • sort -n -r |head -1 | awk '{print $2}' - date orders the directory and outputs the name of the most recently modified

Solution 4

After some experimenting, I came up with the following:

The unix stat command is useful here. The '-t' option causes stat to print its output in terse mode (all in one line), and the 13th element of that terse output is the unix timestamp (seconds since epoch) for the last-modified time. This command will list all directories (and sub-directories) in order from newest-modified to oldest-modified:

find -type d -exec stat -t {} \; | sort -r -n -k 13,13

Hopefully the "terse" mode of stat will remain consistent in future releases of stat !

Here's some explanation of the command-line options used:

find -type d                # only find directories
find -exec [command] {} \;  # execute given command against each *found* file.
sort -r                     # reverse the sort
sort -n                     # numeric sort (100 should not appear before 2!)
sort -k M,N                 # only sort the line using elements M through N.

Returning to your original request, to copy files, maybe try the following. To output just a single directory (the most recent), append this to the command (notice the initial pipe), and feed it all into your 'cp' command with backticks.

| head --lines=1 | sed 's/\ .*$//'

Solution 5

If your directories are named YYYYMMDD like your question suggests, take advantage of the alphabetic globbing.

Put all directories in an array, and then pick the first one:

dirs=(*/); first_dir="$dirs";

(This is actually a shortcut for first_dir="${dirs[0]}";.)

Similarly, for the last one:

dirs=(*/); last_dir="${dirs[$((${#dirs[@]} - 1))]}";

Ugly syntax, but this is what it breaks down to:

# Create an array of all directories inside the working directory.
dirs=(*/);

# Get the number of entries in the array.
num_dirs=${#dirs[@]};

# Calculate the index of the last entry.
last_index=$(($num_dirs - 1));

# Get the value at the last index.
last_dir="${dirs[$last_index]}";

I know this is an old question with an accepted answer, but I think this method is preferable as it does everything in Bash. No reason to spawn extra processes, let alone parse the output of ls. (Which, admittedly, should be fine in this particular case of YYYYMMDD names.)

Share:
23,636

Related videos on Youtube

jdamae
Author by

jdamae

Updated on June 09, 2020

Comments

  • jdamae
    jdamae almost 4 years

    I want to copy the files from the most recent directory created. How would I do so in unix?

    For example, if I have the directories names as date stamp as such:

    /20110311
    /20110318
    /20110325
    
  • Tom Zych
    Tom Zych about 13 years
    In bash you can use $(...) instead of backticks.
  • jdamae
    jdamae about 13 years
    that's basically what i need. Thanks!
  • jdamae
    jdamae about 13 years
    thanks for your suggestions. Very interesting. Can you edit this so I can see the entire command? I'm not sure if i'm trying this correctly. thanks again.
  • jdamae
    jdamae about 13 years
    Actually, this would work well for me in the case that I do need the top 2-3 latest dirs created. ls | tail -2
  • janmoesen
    janmoesen over 11 years
    supertrue: not in Bash, or at least not that I am aware of. Were you trying it in the plain old Bourne shell sh?
  • supertrue
    supertrue over 11 years
    No, I use Bash (Mac Terminal), I was just wondering what the meaning of it was, given that # is also used for comments.
  • janmoesen
    janmoesen over 11 years
    Ah, I see. It has special meaning when it's inside a variables with braces. ${#foo} counts the number of characters in a normal (string) variable called foo, and ${foo[@]} counts the number of elements in an array called foo. See Bash parameter expansion.

Related