0

I have a File structure of :

FOLDER/SUB_FOLDER/Text_File

I have over 1k+ FOLDER and each FOLDER has at least 2 different SUB_FOLDER with each SUB_FOLDER their own Text_File.

I'm trying to challenge myself to generate a list of the most recent Text_File per FOLDER/ (as a root)

My Pseudo code is (as well as commands I know right now): 
List all FOLDERS
 - **ls -t [EACH_FOLDER] | head -n1 **
    **ls -t EACH_FOLDER/SUB_FOLDER/**
      **ls Text_File**

Output should be:

/FOLDER/SUB_FOLDER/Text_File

...

all files.

My Goal is : I need to grep through each LATEST Text_File from each root FOLDER to parse information out of it.

| improve this question | | | | |
0

With gnu you could try:

find "$(pwd)" -mindepth 2 -maxdepth 2 -type d -printf "d%h\0%T@ %p\0" | awk -v RS="\0" '
  /^d/ {directoryname=substr($0,2)}
  /^[0-9]/ && (!lmtimes[directoryname] || lmtimes[directoryname] < $1) {
    lmtimes[directoryname]=$1;
    lmtimedns[directoryname]=substr($0,index($0," ")+1);
  }
  END {for (directoryname in lmtimedns) print lmtimedns[directoryname]}
  '

This version has been tested against weird names which contain special chars: \n " etc.

$(pwd) execute pwd command which prints the absolute pathname of the current directory.

find $(pwd) search the current directory, the full directory pathnames will be printed

The filter -mindepth 2 -maxdepth 2 -type d is selecting only directories at the second level where FOLDER in current directory are at level 1 and their SUB_FOLDER at level 2.

-printf "d%h\0%T@ %p\0" prints for each SUBFOLDER found, this information below:

d FOLDER \0 last modif time in second since EPOCH [space] SUBFOLDER \0 etc.

The \0 cannot be part of a name so this is the perfect delimiter.

awk -v RS="\0" is considering \0 as a Record Separator.

/^d/ {directoryname=substr($0,2)}: this regex is true when a record starts with d; directoryname variable is updated with the FOLDER name which is made of all chars right after the d char, by construction, thanks to printf.

/^[0-9]/ : this regexis true when a record starts with a digit. By construction, thanks to printf, the first field ($1: e.g. all chars up to ̀[space] char) of the current record contains the last modified time.

&& (!lmtimes[directoryname] || lmtimes[directoryname] < $1): lmtimes is an associative array (a Map of [key,value] pairs). It is used to store the newest last modification time of the current SUBFOLDER for the current FOLDER (directoryname). The expression is true if there is not yet a last modified time stored for directoryname or if the already stored last modified time is older than the one from the current SUBFOLDER.

When the later expression is true, both the last modified time and the name of FOLDER are stored using the directoryname key into lmtimes and lmtimedns, respectively.

END {for (...: When all records had been parsed, each SUBFOLDER name with newest last modified time are printed.

----

For history the command to list the filenames with most recent modification time for each directory:

 find "$(pwd)" -depth -type f -printf "d%h\0%T@ %p\0" | awk -v RS="\0" '
  /^d/ {
    directoryname=substr($0,2);
  }
  /^[0-9]/ {
    if (!lmtimes[directoryname] || lmtimes[directoryname] < $1) {
      lmtimes[directoryname]=$1;
      lmtimefns[directoryname]=substr($0,index($0," ")+1);
    }
  }
  END {
    for (directoryname in lmtimefns) {
      print lmtimefns[directoryname];
    }
  }'
| improve this answer | | | | |
  • Thank you Jay. I think there has to be two functions or iterations for this to work. The output here provided the Text_Files for every sub folder... My modification time should be based on folder modification does not need to go down to the FOLDER/SUB_FOLDER/**TEXTFILE. – Bain Apr 22 '16 at 20:46
  • @Bain This new version is listings for each FOLDER the SUB_FOLDER which has the most recent last modification time. – Jay jargot Apr 22 '16 at 21:48
  • Thanks @Jay Jargot, this seemed to have worked correctly. NICE JOB! I wish I could get this good at bash scripts. – Bain Apr 25 '16 at 21:11
  • @Bain great! The answer has been updated with an explanation. – Jay jargot Apr 26 '16 at 11:00
1
#!/bin/bash

# Array of root folders
folders=("a" "b")

# Search all specified root folders
for f in ${folders[@]}; do
    # Descend hierarchy and retrieve modification date of each file with "stat"
    find $f -type f -exec stat -f "%m,%N" {} ';' | \
        # sort by date, most recent first
        sort -gr | \
        # extract first (most recent) file
        head -1 | \
        # return file name only
        cut -d, -f2
done
| improve this answer | | | | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.