it-swarm-eu.dev

Účinně smažte velký adresář obsahující tisíce souborů

Máme problém se složkou, která se stává nepohodlnou se stovkami tisíc malých souborů.

Existuje tolik souborů, které provádějí rm -rf vrátí chybu a místo toho musíme udělat něco jako:

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

Funguje to, ale je velmi pomalé a nedostatek paměti neustále selhává.

Existuje lepší způsob, jak toho dosáhnout? V ideálním případě bych chtěl odstranit celý adresář, aniž by se staral o jeho obsah.

177
Toby

Používání rsync je překvapivé rychlé a jednoduché.

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

@ sarathova odpověď zmínila další rychlou volbu: Perl! Jeho měřítka jsou rychlejší než rsync -a --delete.

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

Zdroje:

  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
238
stevendaniels

Někdo na Twitter navrhl použití -delete namísto -exec rm -f{} \;

To zlepšilo účinnost příkazu, stále však používá rekurzi, aby projel všechno.

42
Toby

A co něco jako: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Počet souborů, které chcete odstranit najednou, můžete omezit změnou argumentu parametru -n. Zahrnuty jsou také názvy souborů s mezerami.

19
digital_infinity

Chytrý trik:

rsync -a --delete empty/ your_folder/

Je to velmi náročné na CPU, ale opravdu rychle. Viz https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files .html

16
MZAweb

Pokud si k jednomu z komentářů přidám komentář, nemyslím si, že děláte to, co si myslíte, že děláte.

Nejprve jsem vytvořil obrovské množství souborů, abych simuloval vaši situaci:

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

Pak jsem zkusil to, co jsem očekával, že selžu, a co to zní, jako byste dělali v otázce:

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

Ale toto funguje funguje:

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

Měl jsem příležitost otestovat -delete ve srovnání s -exec rm \{\} \; a pro mě -delete byla odpověď na tento problém.

Použitím -delete odstranilo soubory ve složce 400 000 souborů nejméně 1 000krát rychleji než rm.

Článek „Jak odstranit velké množství souborů v linuxu“ naznačuje, že je asi třikrát rychlejší, ale v mém testu byl rozdíl mnohem dramatičtější.

10
user2365090

O -delete výše uvedená možnost: Používám ji k odstranění velkého počtu (1M + est) souborů v dočasné složce, kterou jsem vytvořil, a nechtěně jsem zapomněl provést noční vyčištění. Náhodně jsem zaplnil disk/diskový oddíl a nic jiného nemohlo odstranit, ale find . příkaz. Je to pomalé, nejprve jsem používal:

find . -ls -exec rm {} \;

Ale to vyžadovalo EXTRÉMNÍ množství času. Začalo to asi po 15 minutách, aby se odstranily některé soubory, ale myslím, že to odstranilo méně než 10 za sekundu poté, co se konečně začalo. Zkusil jsem tedy:

find . -delete

místo toho, a nechám to běžet hned teď. Zdá se, že běží rychleji, i když se jedná o EXTRÉMNĚ zdanění na procesoru, což nebyl jiný příkaz. Teď to běží už asi hodinu a myslím si, že dostávám prostor zpět na svůj disk a oddíl se postupně "ztenčuje", ale stále to trvá velmi dlouho. Vážně pochybuji, že běží 1000krát rychleji než ostatní. Stejně jako ve všech věcech jsem chtěl poukázat na kompromis v prostoru vs. času. Pokud máte rezervu šířky pásma procesoru (děláme to), spusťte ji. Je spuštěn můj procesor (uptime sestavy):

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

A viděl jsem, že průměrná zátěž přesahuje 30,00, což není dobré pro zaneprázdněný systém, ale pro náš, který je normálně lehce nabitý, je to v pořádku na pár hodin. Zkontroloval jsem většinu dalších věcí v systému a stále reagují, takže zatím jsme v pořádku.

5
Scotty

Zvažte použití svazku Btrfs a jednoduše smažte celý svazek pro takový adresář s velkým počtem souborů.

Případně můžete vytvořit obrazový soubor FS) a poté jej odpojit a smazat a vše rychle odstranit.

4
Sergei

Použijte rm -rf directory namísto rm -rf *.

Zpočátku jsme dělali rm -rf * v adresáři smazat obsah a myšlenku, která byla tak rychlá, jak jen mohla. Ale pak jeden z našich senior inženýrů navrhl, abychom se vyhnuli použití hvězd (*) a místo toho předejte v nadřazeném adresáři, například rm -rf directory.

Po nějaké těžké debatě o tom, jak by to nic nezměnilo, jsme se rozhodli to porovnat, společně s třetí metodou použití find. Zde jsou výsledky:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s

rm -rf directory je asi 9 ČASŮ RYCHLEJŠÍ než rm -rf *!

Netřeba dodávat, že jsme koupili ten technik pivo!

Takže nyní používáme rm -rf directory; mkdir directory pro smazání adresáře a jeho opětovné vytvoření.

4
Joshua Pinter

Existuje několik metod, které lze použít k odstranění velkého počtu souborů v Linuxu. Můžete použít příkaz find with delete, což je rychlejší než možnost exec. Pak můžete použít Perl unlink, pak dokonce rsync. Jak odstranit velké množství souborů v Linux

4
sarath

Za předpokladu, že máte nainstalován GNU parallel), použil jsem toto:

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

a bylo to dost rychlé.

2
Nacho

Smazání adresářů SKUTEČNĚ VELKÝCH vyžaduje jiný přístup, jak jsem se dozvěděl z tento web - budete muset použít ionice. Zajistí (s -c3), že odstranění bude provedeno, pouze pokud systém obsahuje IO- čas na to. Zatížení vašich systémů se nezvýší na vysoké a vše zůstává v pohotovosti (i když můj čas CPU na nalezení byl poměrně vysoký asi na 50%).

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

Pokud máte miliony souborů a každé výše uvedené řešení způsobí váš systém ve stresu, můžete zkusit tuto inspiraci:

Soubor Nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("[email protected]")
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

A nyní smažte soubory:

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

Najít vytvoří dávky (viz getconf ARG_MAX) některých desítek tisíc souborů a předat je Nice_delete. Tím se vytvoří ještě menší dávky, které umožní spánek, když je detekováno přetížení.

1
brablc

Podle toho, jak dobře se musíte těchto souborů zbavit, doporučuji použít shred.

$ shred -zuv folder

pokud chcete adresář vyčistit, ale nemůžete jej odstranit a znovu jej vytvořit, navrhuji jej přesunout a znovu vytvořit okamžitě.

mv folder folder_del
mkdir folder
rm -rf folder_del

to je rychlejší, věřte tomu nebo ne, protože je třeba změnit pouze jeden inode. Pamatujte: Na vícesměrném počítači nemůžete tuto chuť skutečně paralelizovat. Záleží na přístupu na disk, který je omezen RAID nebo tím, co máte.

0
polemon

Skripty Pythonu by neměly být vyhýbány jako nečisté:

#!/usr/bin/python3

import shutil
path_for_deletion = input( 'path of dir for deletion> ' ) 
print( 'about to remove ' + path_for_deletion + ' ...' )
shutil.rmtree( path_for_deletion, ignore_errors=True )
print( '... done' )

Zeptal jsem se chlapa, který provedl několik užitečných benchmarkingu různých metod zde , jestli by to mohl zkusit benchmarking. Z mých experimentů to vypadá docela dobře.

Chyby NB lze zvládnout, aby se alespoň vytiskly ... ale spuštění může být jednodušší trash myDirectoryForDeletion nebo rm -rfv myDirectoryForDeletion později.

0
mike rodent

Pokud se chcete zbavit mnoha souborů co nejdříve ls -f1 /path/to/folder/with/many/files/ | xargs rm by mohlo fungovat dobře, ale lépe jej nespouštějte ve výrobních systémech, protože by se váš systém mohl stát IO problémy a aplikace se mohou během operace mazání zaseknout).

Tento skript funguje dobře pro mnoho souborů a neměl by ovlivňovat ioload systému.

#!/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
0
Leon Kramer

Pro Izkatův nápověda výše:

Ale to funguje :

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

Téměř to fungovalo - nebo by to fungovalo - ale měl jsem nějaké problémy se svolením; soubory byly na serveru, ale stále nechápu, odkud tento problém s povolením přišel. Terminál přesto požádal o potvrzení u každého souboru. Množství souborů bylo kolem 20 000, takže to nebyla možnost. Po "-r" jsem přidal volbu "-f", takže celý příkaz byl "rm -r -f název složky / = ". Pak to vypadalo dobře. Jsem nováček s Terminálem, ale myslím, že to bylo v pořádku, že? Dík!

0
user41527
ls -1 | xargs rm -rf 

by měl fungovat uvnitř hlavní složky

0
PsyStyle

Použijte ls -f | xargs -n 5000 rm, při úpravě -n pro velikost dávky podle vašeho systému (kudos na @digital_infinity pro -n spropitné).

Kromě toho můžete seznam filtrovat pomocí vloženého grepu, např. ls -f | grep '^156' | xargs -n 5000 rm.

Podle mých zkušeností je to mnohem rychlejší než techniky využívající hledání a odstraňuje potřebu složitějších skriptů Shell.

0
buckaroo1177125