Я записал сценарий, который удаляет все кроме последних двух файлов в папке:
#!/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
Этот сценарий будет выполняться как задание крона каждый день.
Обоснование следующие:
Получите список всего использования файлов ls -1
(так, чтобы я получил один файл на строку);
Удалите последние два из использования списка head -n -2
;
С тех пор ls
относительные пути печати, используйте xargs printf
вещь предварительно ожидать путь к папке и сделать это полным путем;
Отправьте их в sudo rm -rf
использование xargs
.
У всех есть доступ к этой папке, таким образом, любой может создать и удалить любые файлы в этой папке.
Проблема: sudo rm -rf
страшно. xargs sudo rm -rf
невероятно страшно.
Я хочу быть уверенным, что никто не может повредить другие папки/системы путем создания умных файлов, которые будут удалены (или случайно или нарочно). Я не знаю, что-то умное как:
file with / spaces.txt
который мог привести к супер страшному sudo rm -rf /
.
Править: Моя ошибка, имена файлов не могут содержать /
, таким образом, этой определенной проблемы не произошло бы, но вопрос о том, существуют ли другие риски, все еще стоит.
Поэтому я использую --quoting-style=shell-always
, это должно предотвратить любые приемы с файлами с пробелами. Но теперь я задаюсь вопросом, мог ли кто-то быть дополнителен умный с пробелами и кавычками в имени файла, возможно.
Действительно ли мой сценарий безопасен?
Примечание: Мне нужно sudo
потому что я получаю доступ к папке удаленно (от использования подключенного сетевого диска mount
), и я не мог заставить это работать без sudo.
В Linux любой символ является допустимым символом образования имени файла кроме:
\0
(ASCII NUL): как используется для строкового завершения в C/
(наклонная черта вправо): как используется для разделения путиТак, Ваш подход не будет определенно работать во многих случаях, как Вы можете предположить, например, делаете он обрабатывает новую строку (\n
) в имени файла? (Подсказка: Нет).
Немного примечаний:
ls
; используйте специальные инструменты (существует по крайней мере один для большинства вариантов использования),xargs
, посмотрите, можно ли сойти с рук find ... -exec
; в большинстве случаев Вы согласитесь только с find
одинЯ думаю, что они получат Вас идущий на данный момент. steeldriver уже обеспечил, NUL разделил идею в комментарии (printf -- '%s\0' /path/to/some/folder/* | head -zn -2 | xargs -0 rm
), используйте это в качестве начальной точки.
xargs
действительно поддерживает некоторое заключение в кавычки: с одинарными кавычками, двойные кавычки или обратная косая черта, которая позволяет этому принимать произвольные аргументы ¹, но с синтаксисом, который отличается от синтаксиса заключения в кавычки подобных Границе оболочек.
Реализация GNU ls
как найдено на Ubuntu не имеет никакого режима заключения в кавычки, который совместим с xargs
формат ввода.
ls --quoting-style=shell-always
совместимо с ksh93, ударом и оболочками zsh, заключающими синтаксис в кавычки, но только когда вывод ls
интерпретируется оболочкой в той же локали как ls
был, когда это произвело его. Кроме того, нужно избежать некоторых локалей, как те, которые используют BIG5, BIG5-HKSCS, GBK или GB18030.
Таким образом с теми оболочками, можно на самом деле сделать:
typeset -a files
eval "files=($(ls --quoting-style=shell-always))"
xargs -r0a <(printf '%s\0' "${files[@]:0:3}") ...
Но это имеет преимущество:
files=(*(N)) # zsh
files=(~(N)*) # ksh93
shopt -s nullglob; files=(*) # bash
Единственный случай, где это становится полезным, - когда Вы хотите использовать -t
опция ls
отсортировать файлы по mtime/atime/ctime или -S
/-V
. Но даже затем, Вы могли бы также использовать zsh
:
files=(*(Nom))
например, отсортировать файлы по mtime (использование oL
для -S
, и n
для -V
).
Удалить всех кроме двух последний раз изменило регулярные файлы:
rm -f -- *(D.om[3,-1])
¹ существуют все еще некоторые ограничения длины ( execve()
и в некотором не-GNU xargs
реализации намного ниже произвольные), и некоторый не-GNU xargs
реализации будут дросселировать входа, который содержит последовательности байтов, не формирующих допустимые символы.