Назад | Перейти на главную страницу

Сервер Ubuntu: удалить первую папку в каталоге

Как я могу захватить первую подпапку в каталоге и удалить ее?

Я нашел скрипт для отслеживания свободного места на диске.

Он отправляет электронное письмо с предупреждением, если место заканчивается, но я также хочу удалить некоторые ненужные вещи.

У меня есть резервная папка, в которой я сохраняю ежедневные и ежемесячные резервные копии. Я хочу удалить первую папку, так как она всегда самая старая, но я не знаю имени самой старой резервной копии.

Мои папки без января-мая и декабря:

06-01
07-01
08-01
09-01
10-01
11-01
Friday
Monday
Saturday
Sunday
Thursday
Tuesday
Wednesday

Как я могу удалить первую папку «06-01», не зная ее имени?

Если вы хотите найти первая подпапка Что касается алфавитно-цифрового порядка (будьте осторожны, это зависит от ваших локальных настроек), вы можете использовать этот небольшой фрагмент Bash:

shopt -s nullglob
shopt -u dotglob
a=( */ )
echo "${a[0]}"

это будет просто эхом первая подпапка относительно буквенно-цифровой сортировки Баша.

Если вы хотите удалить его, добавив несколько охранников:

shopt -s nullglob
shopt -u dotglob
a=( */ )
[[ -d "${a[0]}" ]] && echo rm -rfv -- "${a[0]}"

Я не уверен, что лично буду использовать это на рабочем сервере. Смотря как конечно Я содержимое каталога (и насколько я уверен в резервных копиях).

В shopt -s nullglob и shopt -u dotglob здесь, чтобы избежать глупой ошибки, которая могла бы произойти, если бы они были установлены иначе. Также соблюдайте цитаты и не меняйте их вообще.

О, я оставил echo напротив rm. Удаляйте его только после нескольких проверок, если вы уверены, что он работает именно так, как вы ожидаете. В качестве однострочного:

shopt -s nullglob; shopt -u dotglob; a=( */ ); [[ -d "${a[0]}" ]] && echo rm -rfv -- "${a[0]}"

Если вы хотите указать путь к вложенным папкам, просто замените a=( */ ) заявление с:

a=( /path/to/folder/*/ )

убедитесь, что вы указали абсолютный путь и заканчиваете */ (с косой чертой в конце). Если на вашем пути есть пробелы, используйте кавычки:

a=( '/path with/spaces to/folder/'*/ )

(обратите внимание, как */ находится за пределами цитируемой части, и нет пробелов после закрывающей кавычки и */).


Теперь, если ты действительно хотите определить самую старую подпапку (с определенной неопределенностью, если несколько из них имеют одинаковый возраст), вы можете (вздрогнув) проанализировать вывод ls отсортировать по времени в обратном порядке и взять первое и удалить его, как в:

ls -1tr --group-directories-first /path/to/folder | head -1 | xargs echo rm -rfv

но это не удастся, если нет каталогов (вы удалите самый старый файл вместо этого) или завершиться ошибкой, если есть файлы, содержащие пробелы или забавные символы. Не делай этого.

Вместо этого вы могли бы попросить ls */ без перечисления содержимого каталогов с -d вариант:

ls -1dtr path/to/folder/*/ | head -1 | xargs echo rm -rfv

но это с треском провалилось бы, если бы в имени были пробелы. Не делай этого.

Затем вы можете попытаться исправить это, используя -Q возможность ls (т.е. процитируйте вывод):

ls -1dtQr path/to/folder/*/ | head -1 | xargs echo rm -rfv

но это не удается, если в имени файла есть кавычки или новые строки. Не делай этого.

Тогда ты бы попробовал xargs с -0 вариант:

ls -1dtQr path/to/folder/*/ | head -1 | xargs -0 echo rm -rfv

но это не удается, если в имени файла есть символы новой строки. Не делай этого.

Тогда ты мог ... СТОП!

Если вам действительно нужен 100% пуленепробиваемый метод, он может быть не самым эффективным, но он подойдет вам, если безопасность является вашим главным приоритетом, вот возможность (в Bash):

shopt -s nullglob
shopt -u dotglob
where="/path with spaces is ok/to/folder"
for i in "$where"/*/; do
    if ! find "$where" -mindepth 1 -maxdepth 1 \! -name '.*' -type d \! -newer "$i" \! -samefile "$i" -print | read; then
        echo rm -rfv -- "$i"
        break
    fi
done

Это не самый эффективный вариант, но работает очень хорошо: он перебирает все каталоги (первого уровня). i в данном каталоге where и запускает find чтобы (не скрытые) каталоги были старше, чем каталог i а если находит, то ничего не делает; если не находит, то ломаем echo rm это и разорвать петлю. Побочным эффектом является то, что каталог, который будет удален, является самым старым и первым в алфавитно-цифровом порядке Bash.

Вы даже можете сделать из него классный сценарий (назовите его, например, rm_oldest_dir):

#!/bin/bash

if [[ $1 = --serious ]]; then
    serious=()
    shift
else
    serious=("echo")
fi

if [[ -z $1 ]]; then
    echo >&2 "You must provide an argument"
    exit 1
fi

where=$1

if [[ ! -d $where ]]; then
    echo >&2 "\`$where' is not a directory"
    exit 1
fi

shopt -s nullglob
shopt -u dotglob
for i in "$where"/*/; do
    if ! find "$where" -mindepth 1 -maxdepth 1 \! -name '.*' -type d \! -newer "$i" \! -samefile "$i" -print | read; then
        "${serious[@]}" rm -rfv -- "$i"
        if ((${#serious[@]})); then
            echo "*** Nothing has been removed. Call with option --serious to really remove. ***"
        fi
        break
    fi
done

Затем используйте, например, как

$ mkdir Test
$ cd Test
$ mkdir oldest; sleep 1; mkdir lots_of_dirs{1..10}
$ rm_oldest_dir .
rm -rfv -- ./oldest/
*** Nothing has been removed. Call with option --serious to really remove. ***
$ ls
lots_of_dirs1   lots_of_dirs3  lots_of_dirs6  lots_of_dirs9
lots_of_dirs10  lots_of_dirs4  lots_of_dirs7  oldest
lots_of_dirs2   lots_of_dirs5  lots_of_dirs8
$ rm_oldest_dir --serious .
removed directory: `./oldest'
$ ls
lots_of_dirs1   lots_of_dirs2  lots_of_dirs4  lots_of_dirs6  lots_of_dirs8
lots_of_dirs10  lots_of_dirs3  lots_of_dirs5  lots_of_dirs7  lots_of_dirs9
$

Аккуратно.

Затем вы можете поместить его в свой crontab как

0 0 * * * rm_oldest_dir --serious "/path with spaces/to/where/you/want"

Единственная атака на этот скрипт, о которой я могу думать, - это слишком много папок: глобализация в Bash не очень эффективна, а слишком много папок может привести к очень высокой загрузке ЦП в течение длительного времени и, в конечном итоге, закончиться прерыванием. Более сложный метод - это быстрая сортировка на основе файлов, но поскольку этот пост уже слишком длинный, я закончу его здесь.

Ура!


Я не знаю, действительно ли вторая часть этого ответа имеет место в научной фантастике. Если нет, дайте мне знать в комментариях или проголосуйте против этого сообщения!