xargs and find, rm complaining about \n (newline) in filename
Solution 1
The ls
appends a newline and the last xargs -0 says the newline is part of the file name.
Run the last xargs with -d '\n'
instead of -0
.
BTW, due to the way xargs works, your whole pipe is a bug waiting to happen. Consider a really long file name list produced by the find
, so that the xargs -0 ls
runs ls
multiple times with subsets of the filenames. Only the oldest of the last ls
invocation will make it past the tail -1
. If the oldest file is actually, say, the very first filename output by find
, you are deleting a younger file.
Solution 2
Any solution involving ls
is absolutely wrong.
The correct way to do this is to use find
to fetch the set of files, sort
to order them chronologically, filter out all but the first, then rm
to delete. @Ken had this mostly right, missing only a few details.
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -printf '%T@ %p\0' |\
sort -z -n | \
{ IFS= read -d '' file ; [ -n "$file" ] && echo rm -f "$(cut -d' ' -f2- <<<"$file")" ; }
Remove the echo
above to actually perform the deletion.
The above code works even for files which have spaces, newlines or other unusual values in the file names. It will also do nothing harmful when there are no results.
If you don't care about breaking on newlines in filenames this gets a bit easier
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -printf '%T@ %p\n' |\
sort -n |\
head -n 1 |\
cut -d' ' -f2- |\
xargs echo rm
The difference is that we can rely on head
and can use cut
on a pipe instead of doing anything crazy.
Solution 3
ls
emits newlines as separators, so you need to replace the second xargs -0
with xargs -d '\n'
. Breaks, though, if the oldest file has a newline in its name.
Solution 4
You can also use find to print out the modification time, sort, cut and xargs at will:
find /home/backups -printf "%T@ %p\n" | sort -n | head -1 | cut -d" " -f2- | xargs ls -al
user1076412
Updated on June 12, 2022Comments
-
user1076412 almost 2 years
I am trying to delete the oldest file in a tree with a script in Debian.
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -print0 | xargs -0 ls -t | tail -1 | xargs -0 rm
But I am getting an error:
rm: cannot remove `/home/backups/tree/structure/file.2011-12-08_03-01-01.sql.gz\n': No such file or directory
Any ideas what I am doing wrong (or is there an easier/better way?), I have tried to RTFM, but am lost.