Ефективно видаліть великий каталог, що містить тисячі файлів


159

У нас виникла проблема з тим, що папка стає непростою із сотнями тисяч крихітних файлів.

Існує так багато файлів, що при виконанні rm -rfповертається помилка, і замість цього нам потрібно зробити щось на кшталт:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

Це працює, але дуже повільно і постійно втрачає пам'ять.

Чи є кращий спосіб зробити це? В ідеалі я хотів би видалити весь каталог, не піклуючись про вміст всередині нього.


16
rm -rf *в папці, ймовірно, не вдається через занадто багато аргументів; а як бути, rm -rf folder/якщо ви хочете все-таки видалити весь каталог?
sr_

4
Замість того, щоб видаляти її вручну, я пропоную встановити папку на окремому розділі та просто відключити формат && & & reount.
bbaja42

7
Просто з цікавості - скільки файлів потрібно, щоб зламати rm -rf?
jw013

7
Напевно, ви повинні перейменувати питання на щось більш точне, наприклад, "Ефективно видалити великий каталог, що містить тисячі файлів". Для видалення каталогу та його вмісту необхідна рекурсія за визначенням. Ви можете вручну від’єднати лише сам каталог inode (ймовірно, вимагає кореневих привілеїв), відключити файлову систему та запустити fsckїї, щоб відновити невикористані блоки диска, але такий підхід здається ризикованим і може не бути швидшим. Крім того, перевірка файлової системи може включати рекурсивне пересування дерева файлової системи в будь-якому випадку.
jw013

4
Після того, як у мене ccacheдерево файлів було таким величезним і rmзабирало так довго (і робила всю систему млявою), було значно швидше скопіювати всі інші файли з файлової системи, форматувати та скопіювати їх назад. З тих пір я даю таким масивним малим файловим деревам власну виділену файлову систему, тож ви можете mkfsбезпосередньо замість цього rm.
frostschutz

Відповіді:


211

Використання rsync дивно швидко та просто.

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

У відповіді Сарата згадується ще один швидкий вибір: Perl! Його орієнтири швидше, ніж rsync -a --delete.

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'

Джерела:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux

4
Дякую, дуже корисно. Я використовую rsync весь час, я не мав уявлення, що ви можете використовувати його для видалення, як це. Значно швидше, ніж rm -rf
Джон Пауелл,

22
rsyncможе бути швидшим, ніж звичайний rm, тому що це гарантує делетів у правильному порядку, тому потрібно менше обчислень. Дивіться цю відповідь serverfault.com/a/328305/105902
Marki555

7
Чи може хтось змінити вираз perl, щоб рекурсивно видалити всі каталоги та файли всередині каталогу_to_be_deleted ?
Абхінав

5
Примітки: додати -Pможливість Rsync ще деякий дисплея, а також, бути обережними про синтаксис, то замикають косі є обов'язковими. Нарешті, ви можете запустити команду rsync вперше з -nможливістю спочатку запустити сухий запуск .
Drasill

1
-aодно -rlptgoD, але для видалення тільки -rdнеобхідно
Коен.

38

Хтось із Twitter запропонував використовувати -deleteзамість цього-exec rm -f{} \;

Це підвищило ефективність команди, вона все ще використовує рекурсію, щоб пройти все, хоча.


11
Це нестандартно. GNU findє -delete, а findможе бути й інше .
enzotib

13
-deleteзавжди слід віддавати перевагу, -exec rmякщо вони є, з міркувань безпеки та ефективності.
jw013

6
GNU - це фактично стандарт.
RonJohn

17

А як щодо чогось такого: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Ви можете обмежити кількість файлів для видалення відразу, змінивши аргумент для параметра -n. Також входять імена файлів із пробілами.


2
Вам, мабуть, не потрібен -n 20біт, оскільки xargs в будь-якому випадку повинен обмежувати себе прийнятними розмірами списку аргументів.
Марно

Так, ти правий. Ось записка man xargs: (...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec. Таким чином, -nваріант є для таких випадків, коли xargs не може визначити розмір буфера CLI або якщо виконана команда має деякі обмеження.
digital_infinity

12

Розумний трюк:

rsync -a --delete empty/ your_folder/

Це супер CPU інтенсивно, але дійсно дуже швидко. Дивіться https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html


Це не так швидко, тому що він читає вміст каталогу неефективно. Дивіться цю відповідь на 10 разів швидше рішення та пояснення serverfault.com/a/328305/105902
Marki555

2
@ Marki555: у редагуванні питання повідомляється 60 секунд rsync -a --deleteпроти 43 за lsdent. Співвідношення 10x було для time ls -1 | wc -l vs time ./dentls bigfolder >out.txt(це частково справедливе порівняння через > filevs wc -l).
Гастур

Проблема в тому , що існує NONE команд там на самому ділі не робити необхідну операцію обходу для видалення. Код, який вони дають? НЕ ПРАЦЮЄ, як описано в Marki555.
Швартальф

11

Розкриваючи один із коментарів, я не думаю, що ти робиш те, що думаєш, що робиш.

Спочатку я створив величезну кількість файлів, щоб імітувати вашу ситуацію:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

Потім я спробував те, що, напевно, зазнав невдачі, і як це виглядає, як ви робите, у питанні:

$ rm -r foo/*
bash: /bin/rm: Argument list too long

Але це робить роботу:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

6
Це єдине рішення, яке спрацювало: запустіть rm -Rf bigdirectoryкілька разів. У мене був каталог з тисячами мільйонів підкаталогів і файлів. Я навіть не міг працювати lsабо findчи rsyncв цій директорії, так як він вибіг з пам'яті. Команда rm -Rfбагато разів виходила (з пам'яті), лише видаляючи частину мільярдів файлів. Але після багатьох спроб, нарешті, це зробило роботу. Здається, це єдине рішення, якщо проблема не вистачає.
Ерік

6

У мене була можливість протестувати -deleteв порівнянні з, -exec rm \{\} \;і для мене -deleteбула відповідь на цю проблему.

Використання -deleteвидалених файлів у папці з 400 000 файлів принаймні в 1000 разів швидше, ніж rm.

У статті "Як видалити велику кількість файлів у linux" випливає, що це приблизно втричі швидше, але в моєму тесті різниця була набагато драматичнішою.


3
Використання команди find -execвиконує rmкоманду для кожного файлу окремо, тому це так повільно.
Marki555

5

Про -deleteпараметр вище: я використовую його для видалення великої кількості файлів (1M + est) у темп-папці, яку я створив, і мимоволі забув очищати щоночі. Я заповнив диск / розділ випадково, і більше нічого не могло їх видалити, крім find .команди. Це повільно, спочатку я використовував:

find . -ls -exec rm {} \;

Але це займало ЕКСТРЕМНУ кількість часу. Він почав приблизно через 15 хвилин, щоб видалити деякі файли, але я здогадуюсь, що після остаточного запуску він видаляв менше 10 секунд за секунду. Отже, я спробував:

find . -delete

натомість, і я даю йому працювати зараз. Здається, вона працює швидше, хоча НАДНОГО оподаткування процесора, що інша команда не була. Зараз він працює вже близько години, і я думаю, що я повертаю простір на своєму приводі, і перегородка поступово "схудла", але це ще дуже довго займає. Я серйозно сумніваюся, що він працює в 1000 разів швидше, ніж інший. Як і у всьому, я просто хотів зазначити компроміс у просторі та в часі. Якщо у вас є запас пропускної здатності процесора (ми це робимо), тоді запустіть останню. У мене працює CPU ( uptimeзвіти):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

І я бачив, як середнє завантаження перевищує 30.00, що не годиться для зайнятої системи, але для нашої, яка зазвичай мало завантажена, це нормально за пару годин. Я перевірив більшість інших речей у системі, і вони все ще реагують, тому ми зараз у порядку.


якщо ви збираєтесь використовувати, execви майже напевно не хочете використовувати, -lsа " find . -type f -exec rm '{}' ++" - це швидше, тому що це дасть стільки аргументів на rm, скільки можна обробити відразу.
ксенотеррацид

Я думаю, ви повинні продовжити і відредагувати це у власну відповідь ... це дійсно занадто довго для коментарів. Крім того, це здається, що ваша файлова система має досить дорогі видалення, цікаво, яка вона? Ви можете запустити це find … -deleteчерез niceабо ionice, що може допомогти. Тож можливо змінити деякі параметри кріплення на менш безпечні налаштування. (І, звичайно, залежно від того, що ще є у файловій системі, найшвидший спосіб видалити все часто mkfs.)
derobert

3
Середня завантаженість не завжди є процесором, це лише показник кількості заблокованих процесів за час. Процеси можуть блокувати на вході / виводу диска, що, ймовірно, відбувається тут.
Score_Under

Також зауважте, що середня завантаженість не враховує кількість логічних процесорів. Отже, loadavg 1для одноядерної машини такий же, як loadavg 64для 64-ядерної системи - це означає, що кожен процесор зайнятий 100% часу.
Marki555


3

Подумайте про використання тома Btrfs і просто видаліть цілий том для такої директорії з великою кількістю файлів.

Крім того, ви можете створити файл зображення FS, потім відключити та видалити його, щоб видалити все дуже швидко.


2

Припускаючи, що parallelвстановлено GNU , я використав це:

parallel rm -rf dir/{} ::: `ls -f dir/`

і це було досить швидко


1

Для видалення каталогів ДУЖЕ ВЕЛИКІ потрібен інший підхід, як я дізнався на цьому веб-сайті - вам потрібно буде використовувати ionice. Це гарантує (з -c3), що видалення виконуватиметься лише тоді, коли система має для цього IO-час. У вас завантаження систем не підвищиться до високого, і все залишається чуйним (хоча час мого процесора на пошук був досить високим - приблизно 50%).

find <dir> -type f -exec ionice -c3 rm {} \;

5
використання +замість цього \;зробить це швидше, оскільки він передає більше аргументів до rm одразу, менше
розщеплюючи

1
Чому б і ні ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

має працювати всередині основної папки


1
lsне працюватиме через кількість файлів у папці. Ось чому мені довелося користуватися find, хоча дякую.
Тобі

4
@Toby: Спробуйте ls -f, що відключає сортування. Сортування вимагає, щоб весь каталог був завантажений у пам’ять, щоб його сортувати. Несортований lsповинен мати можливість передавати свій вихід.
camh

1
Не працює з назви файлів, які містять нові рядки.
maxschlepzig

@camh це правда. Але видалення файлів у відсортованому порядку відбувається швидше, ніж у несортованому (через перерахунок btree каталогу після кожного видалення). Дивіться цю відповідь на прикладі serverfault.com/a/328305/105902
Marki555

@maxschlepzig для таких файлів ви можете використовувати find . -print0 | xargs -0 rm, які використовуватимуть NULL char як роздільник імен файлів.
Marki555

0

Для підказки Ізката вище:

Але це робить роботу:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

Це майже спрацювало - або працювало б - але у мене були деякі проблеми з дозволом; Файли були на сервері, але я все ще не розумію, звідки ця проблема з дозволом. У будь-якому випадку, Термінал просив підтвердження для кожного файлу. Кількість файлів становила близько 20 000, тому це не було можливим. Після "-r" я додав варіант "-f", тому вся команда була " rm -r -f ім'я папки / ". Тоді здавалося, що це справно працює. Я початківець з Терміналом, але, мабуть, це було нормально, правда? Дякую!


0

Залежно від того, наскільки добре вам потрібно позбутися цих файлів, я б запропонував використовувати shred.

$ shred -zuv folder

якщо ви хочете очистити каталог, але ви не можете його видалити та відтворити, я пропоную перемістити його та створити його миттєво.

mv folder folder_del
mkdir folder
rm -rf folder_del

це швидше, вірте чи ні, так як потрібно змінити лише одну вкладку. Пам'ятайте: Ви не можете реально паралелізувати цей смак на багатоядерному комп'ютері. Це зводиться до доступу до диска, який обмежений RAID або тим, що у вас є.


1
shred не працюватиме з багатьма сучасними файловими системами.

0

Якщо у вас мільйони файлів, і кожне рішення, що перераховується вище, переживає вашу систему в стресі, можете спробувати це натхнення:

Файл nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("$@")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

А тепер видаліть файли:

find /path/to/folder -type f -exec ./nice_delete {} \+

Find створить партії (див. getconf ARG_MAX) З десятків тисяч файлів і передасть їх nice_delete. Це створить ще менші партії, які дозволять спати, коли буде виявлено перевантаження.


0

Якщо ви просто хочете якнайшвидше позбутися багатьох файлів, це ls -f1 /path/to/folder/with/many/files/ | xargs rmможе спрацювати нормально, але краще не запускати його на виробничих системах, оскільки ваша система може стати проблемами вводу-виводу, а додатки можуть застрягти під час операції видалення.

Цей сценарій чудово працює для багатьох файлів і не повинен впливати на завантаженість системи.

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.