I wrote a script that deletes all except the last two files in a folder:
#!/bin/bash
ls -1 --quoting-style=shell-always /path/to/some/folder \
| head -n -2 \
| xargs printf -- "'/path/to/some/folder/%s'\n" \
| xargs sudo rm -rf
This script will be executed as a cron job every day.
The reasoning is as follows:
-
Obtain a list of all files using
ls -1
(so that I get one file per line); -
Remove the last two from the list using
head -n -2
; -
Since
ls
prints relative paths, use thexargs printf
thing to prepend the folder path and make it an absolute path; -
Send them to
sudo rm -rf
usingxargs
.
Everyone has access to this folder, so anyone can create and delete any files in this folder.
The problem is: sudo rm -rf
is scary. xargs sudo rm -rf
is incredibly scary.
I want to be sure that no one can damage other folders/systems by creating clever files to be deleted (either accidentally or on purpose). I don't know, something clever like:
file with / spaces.txt
which could result in a super scary sudo rm -rf /
.
EDIT: My mistake, file names cannot contain /
, so this specific problem wouldn't happen, but the question about whether or not there are other risks still stands.
This is why I am using --quoting-style=shell-always
, this should prevent any tricks with files with spaces. But now I am wondering if someone could be extra clever with spaces and quotes in the filename, perhaps.
Is my script safe?
Note: I need sudo
because I am acessing the folder remotely (from a mapped network drive using mount
), and I couldn't get it to work without sudo.
Best Answer
In Linux, any character is a valid filename constituting character except:
\0
(ASCII NUL): as used for string termination in C/
(forward slash): as used for path separationSo, your approach will definitely not work in many cases as you can imagine e.g. does it handle a newline (
\n
) in filename? (Hint: No).Few notes:
ls
; use dedicated tools (there is at least one for most use cases)xargs
, see if you can get away withfind ... -exec
; in most cases, you will be fine with justfind
aloneI think these will get you going for now. steeldriver already provided the NUL separated idea in the comment (
printf -- '%s\0' /path/to/some/folder/* | head -zn -2 | xargs -0 rm
), use this as a starting point.