I referred the following thread How to delete the oldest directory in a given directory? and the accepted solution is perfect. However, I have a requirement to exempt one folder that is the oldest. How I can accommodate this requirement within the solution provided?
5 Answers
One "sneaky" way of doing it would be to change the timestamp of the excluded directory at the start, and restoring its timestamp at the end:
$ cd "$(mktemp --directory)"
$ echo foo > example.txt
$ modified="$(date --reference=example.txt +%s)" # Get its original modification time
$ touch example.txt # Set the modification time to now
[delete the oldest file]
$ touch --date="@$modified" example.txt # Restore; the "@" denotes a timestamp
Usual caveats apply:
- This will fail to restore the original timestamp if killed before completing (or in case of power loss, etc.). If it's really critical to restore the timestamp you could use
touch --reference="$path" "${path}.timestamp"
to save the timestamp to an actual file and restore usingtouch --reference="${path}.timestamp" "$path"
. - The option names are based on GNU coretools. You may have to use less readable option names to do the same thing on other *nixes.

- 51,350
You can adapt the original solution to read files until it finds one that is not excluded:
while IFS= read -r -d '' line
do
file="${line#* }"
if [ "$file" = './my-excluded-directory' ]
then
continue
fi
[do stuff with $file]
break
done < <(find . -maxdepth 1 -type d -printf '%T@ %p\0' | sort -z -n)
(-d ''
is equivalent to the original, because you can't have NUL characters in strings.)
read
ing a long list is slow though, and @mosvy is right that you can do the filtering with some rather nasty find
syntax:
IFS= read -r -d '' < <(find . -maxdepth 1 -type d \( -name 'my-excluded-directory' -prune -false \) -o -printf '%T@ %p\0' | sort -z -n)
file="${REPLY#* }"
# do something with $file here

- 51,350
No, that solution is not perfect, because it depends on a lot of highly non-portable features (find -printf
, sort -z
, read -d
, etc).
My solution isn't perfect either, as it depends on the -ot
operator of test
(which tests if a file is older than another); however that seems to be much better supported (*bsd, busybox, solaris, linux).
# usage with_2nd_oldest 'command' files ...
with_2nd_oldest(){
cmd="$1"; shift
oz="$1"; shift; oy=$1
for f; do
if [ "$f" -ot "$oz" ]; then oy=$oz oz=$f
elif [ "$f" -ot "$oy" -a "$f" != "$oz" ]; then oy=$f
fi
done
$cmd "$oy"
}
$ with_2nd_oldest 'echo rm -fr --' dir/*/
This is also able to handle duplicate arguments:
$ for i in `seq 1 9`; do mkdir -p $i; sleep 1; done
$ with_2nd_oldest echo 7 7 1 1 3 3 2 2 8 9 5 1
2
For the other older question, where the very oldest file/directory was required, it's even more simple:
with_oldest(){
cmd="$1"; shift
oz="$1"; shift
for f; do test "$f" -ot "$oz" && oz=$f; done
$cmd "$oz"
}
Both can be trivially adapted to skip arbitrary paths, or to read the list of files from stdin.
With zsh
:
set -o extendedglob # best in ~/.zshrc
rm -rf -- ^that-folder-to-keep(D/Om[1])
With the solution provided at that other Q&A:
IFS= read -r -d '' line < <(
find . -maxdepth 1 \
! -name that-folder-to-keep \
-type d -printf '%T@ %p\0' 2>/dev/null | sort -z -n) &&
rm -rf "${line#* }"
If you want to remove the second oldest:
zsh
:
rm -rf -- *(D/Om[2])
GNU utilities:
{ IFS= read -r -d '' line &&
IFS= read -r -d '' line &&; } < <(
find . -maxdepth 1 \
-type d -printf '%T@ %p\0' 2>/dev/null | sort -z -n) &&
rm -rf "${line#* }"

- 544,893
#!/bin/bash
while IFS= read -r -d '' line
do
file="${line#* }"
if [ "$file" = './Development_Instance' ]
then
continue
fi
if [ "$file" = './lost+found' ]
then
continue
fi
echo $file
break
done < <(find . -maxdepth 1 -type d -printf '%T@ %p\0' | sort -z -n)
That's how I managed. I know it is not the elegant way to do it. It just does the thing for me.

- 113
./my-excluded-directory
with the! -path
or! -name
option offind
? – Sep 30 '18 at 08:04