Trying to delete all but most recent 2 files in sub directories
Unlike the existing answer, this one NUL-delimits the output from find, and is thus safe for filenames with absolutely any legal character -- a set which includes newlines:
delete_all_but_last() {
local count=$1
local dir=${2:-.}
[[ $dir = -* ]] && dir=./$dir
while IFS='' read -r -d '' entry; do
if ((--count < 0)); then
filename=${entry#*$'\t'}
rm -- "$filename"
fi
done < <(find "$dir" \
-mindepth 1 \
-maxdepth 1 \
-type f \
-printf '%T@\t%P\0' \
| sort -rnz)
}
# example uses:
delete_all_but_last 5
delete_all_but_last 10 /tmp
Note that it requires GNU find and GNU sort. (The existing answer also requires GNU find).
Delete All But The Newest File of Pattern In Each Subdirectory
If you want to remove all files LIVE_DATA_*
except the most recent one on a per-folder basis you could do something like this:
$root = 'C:\path\to\root\folder'
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer } | ForEach-Object {
Get-ChildItem (Join-Path $_.FullName 'LIVE_DATA_*') |
Sort-Object Name -Desc |
Select-Object -Skip 1 |
Remove-Item -Force
}
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer }
lists all subfolders of $root
. Then the ForEach-Object
runs another Get-ChildItem
statement (without recursion) for each subfolder separately. The Join-Path
statement builds a wildcard path from the filename pattern and the full path to the folder (C:\path\to\root\folder\sub\folder\LIVE_DATA_*
).
Basically the code lists all folders, then processes the files for each individual folder.
How to delete all but the most recent files in a directory of folders and files
You can try this:
$Path = "C:\Users\user\Desktop\TEST"
$Folders = Get-ChildItem $Path
foreach ($Folder in $Folders)
{
$FolderName = $Folder.FullName
$Files = Get-ChildItem -Path $FolderName
$FileNumber = $Files.Count - 1
$Files | sort CreationTime -Descending | select -last $FileNumber | Remove-Item -Force -WhatIf
}
Delete all but the most recent X files in bash
For Linux (GNU tools), an efficient & robust way to keep the n
newest files in the current directory while removing the rest:
n=5
find . -maxdepth 1 -type f -printf '%T@ %p\0' |
sort -z -nrt ' ' -k1,1 |
sed -z -e "1,${n}d" -e 's/[^ ]* //' |
xargs -0r rm -f
For BSD, find
doesn't have the -printf
predicate, stat
can't output NULL bytes, and sed
+ awk
can't handle NULL
-delimited records.
Here's a solution that doesn't support newlines in paths but that safeguards against them by filtering them out:
#!/bin/bash
n=5
find . -maxdepth 1 -type f ! -path $'*\n*' -exec stat -f '%.9Fm %N' {} + |
sort -nrt ' ' -k1,1 |
awk -v n="$n" -F'^[^ ]* ' 'NR > n {printf "%s%c", $2, 0}' |
xargs -0 rm -f
note: I'm using bash
because of the $'\n'
notation. For sh
you can define a variable containing a literal newline and use it instead.
Solution for UNIX & Linux (inspired from AIX/HP-UX/SunOS/BSD/Linux ls -b
):
Some platforms don't provide find -printf
, nor stat
, nor support NUL
-delimited records with stat
/sort
/awk
/sed
/xargs
. That's why using perl
is probably the most portable way to tackle the problem, because it is available by default in almost every OS.
I could have written the whole thing in perl
but I didn't. I only use it for substituting stat
and for encoding-decoding-escaping the filenames. The core logic is the same as the previous solutions and is implemented with POSIX tools.
note: perl
's default stat
has a resolution of a second, but starting from perl-5.8.9
you can get sub-second resolution with the stat
function of the module Time::HiRes
(when both the OS and the filesystem support it). That's what I'm using here; if your perl
doesn't provide it then you can remove the ‑MTime::HiRes=stat
from the command line.
n=5
find . '(' -name '.' -o -prune ')' -type f -exec \
perl -MTime::HiRes=stat -le '
foreach (@ARGV) {
@st = stat($_);
if ( @st > 0 ) {
s/([\\\n])/sprintf( "\\%03o", ord($1) )/ge;
print sprintf( "%.9f %s", $st[9], $_ );
}
else { print STDERR "stat: $_: $!"; }
}
' {} + |
sort -nrt ' ' -k1,1 |
sed -e "1,${n}d" -e 's/[^ ]* //' |
perl -l -ne '
s/\\([0-7]{3})/chr(oct($1))/ge;
s/(["\n])/"\\$1"/g;
print "\"$_\"";
' |
xargs -E '' sh -c '[ "$#" -gt 0 ] && rm -f "$@"' sh
Explanations:
For each file found, the first
perl
gets the modification time and outputs it along the encoded filename (eachnewline
andbackslash
characters are replaced with the literals\012
and\134
respectively).Now each
time filename
is guaranteed to be single-line, so POSIXsort
andsed
can safely work with this stream.The second
perl
decodes the filenames and escapes them for POSIXxargs
.Lastly,
xargs
callsrm
for deleting the files. Thesh
command is a trick that preventsxargs
from runningrm
when there's no files to delete.
Recursively delete all but the one newest file throughout all directories
I think the following script should do the trick for you.
#!/bin/bash
DIR_TO_FIND="/path/to/dir"
find "$DIR_TO_FIND" -type d | while read -r DIR; do
cd "$DIR"
ls -t | tail -n +2 | xargs -d '\n' rm -f
cd "$DIR_TO_FIND"
done
delete all but the last match
#!/bin/bash
shopt -s globstar
for dir in **/; do
files=("$dir"file*)
unset 'files[-1]'
rm "${files[@]}"
done
delete all but X most recent folders
This will keep the 10 latest log files based on modification date:
@echo off
for /f "skip=10 delims=" %%a in (' dir *.log /o-d /a-d /b ') do echo del "%%a"
Remove the echo to make it perform the deletions rather than just display them.
Related Topics
How to Simulate a Iret on Linux X86_64
How to Lock The Cursor to The Inside of a Window on Linux
How to Create a File in Assembly with a Dynamically Specified File Path
Running Meteor Application on a Single Core
Linux Configuration - Ssmtp: Cannot Open Smtp.Gmail.Com:587
How to Use 9-Bit Serial Communication in Linux
How to Install G++ on Centos Without Root
Bash Cut Columns to One File and Save onto The End of Another File
Why Does Bash Not Stop on Error for Failures in Sequence of Short-Circuited Commands
How to Rename a Bunch of Files to Eliminate Quote Marks
How to Get Pyinstaller to Working on Ubuntu
Where The Structure "Struct Page" Is Stored on The Linux Kernel
How to Generic .Htaccess to Prevent Hotlink
Difference Between $() and () in Bash
On Linux, Is Access() Faster Than Stat()
Error Hh604: Error Running JSON-Rpc Server: Error:0308010C:Digital Envelope Routines::Unsupported