0

I am trying to write a script in bash that will determine the oldest directory in a file structure.

In this example, I have four directories with the following titles that mimic the date and time they were created. The files are 2022-02-21:20:30:23, 2022-02-21:22:30:23, 2022-02-28:22:30:23, and 2023-02-28:22:30:23. In this case, the dates are arbitrary and were just developed to test the script.

I want the script to identify the directories that exist within this directory, and based on the name of the directory, identify which one is the oldest directory.

My initial attempt at doing this is shown below, and yes, I know the strings are not properly declared as dates, but I do not know how to do this and could use some suggestions.

oldest="1899-01-01:01:01:01"
dirs=`ls -d */`
for i in $dirs ; do
    if [[ oldest < $i  ]] ; then
        oldest=$i
    fi
done
echo $oldest
3
  • Is using the filename necessary or would it be possible to use the last modified time? Feb 22 at 4:46
  • It's unclear whether you have directories that you want to process the names of, or whether you have files within subdirectories that you want to process the names of. You move between talking about "files" and "directories" and it's unclear which of these you mean.
    – they
    Feb 22 at 7:12
  • Related, if not a duplicate - calculate the time elapsed between two timestamps
    – roaima
    Feb 22 at 11:17

3 Answers 3

2

(I'm assuming that the naming convention that you show is the convention used for your directories and that you want to find the oldest directory. I'm ignoring the files within those directories.)

By virtue of your naming convention, your directory names are automatically sorted correctly by expanding the shell glob */ so that the oldest one comes first in the expansion. The shell will, by default, give you the matching names in lexicographic order.

This means that you can get the oldest and newest directories by expanding the */ globbing pattern (assuming that it is matching anything at all), storing the result in an array, and looking at the first and last element of that array:

dirs=( */ )
printf 'Oldest dir by name is "%s"\n' "${dirs[0]}"
printf 'Newest dir by name is "%s"\n' "${dirs[-1]}"

Note that "Oldest/Newest by name" above actually means "Sorts first/last in lexicographic order".

Would you want to remove the trailing / of the directory path that you output, use a standard parameter substitution:

dirs=( */ )
printf 'Oldest dir by name is "%s"\n' "${dirs[0]%/}"
printf 'Newest dir by name is "%s"\n' "${dirs[-1]%/}"
2

If the filenames are all in that YYYY-MM-DD:HH:MM:SS format, and the filenames are all that matter, then you can just sort them lexicographically. For example, this should be the oldest folder by name:

printf "%s\n" */ | sort | head -n1
0

Are the filenames always in the form YYYY-mm-dd:HH:MM:ss? If so, that makes it easier since we only have to handle with the numbers. Using sort, like @muru already mentioned, would be the most intuitive way. Like this: ls -d --format=single-column */ | sort | head -n 1

If you want to use the modification date, you can use ls directly:

ls -dt --format=single-column */ | head -n 1 # most recent modification date
ls -dt --format=single-column */ | tail -n 1 # oldest modification date

-d: Show only directories; -t: Sort by date, newest first; single-column: Show only (file)names; */: Filter directories

The classical if a < b; then min = b loop is the default way to find the largest/smallest number of a set in bash. But you can also translate the date string into a number using date, which allows you to use the bash builtin [ .. -t .. ]. Although this does not work in your specific case - date cannot parse the date from the time here because of the first colon (YYYY-mm-dd:HH:MM:SS).

# mind the space ---v
filename='1989-06-08 12:42:00'
number=$(date -d "$filename" '+%s'))
# 'date' values can directly be compared:
now=$(date '+%s')
if [ number -lt  now ]; then
  echo $(date -d "number") was in the past.
else
  echo $(date -d "number") is in the future.
fi
  

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.