Mam kilkaset plików PDF w katalogu w systemie UNIX. Nazwy plików PDF są naprawdę długie (około 60 znaków).
Kiedy próbuję usunąć wszystkie pliki PDF razem za pomocą następującego polecenia:
rm -f *.pdf
Otrzymuję następujący błąd:
/bin/rm: cannot execute [Argument list too long]
Jakie jest rozwiązanie tego błędu? Czy ten błąd występuje na mv
i cp
poleceń, jak również? Jeśli tak, jak rozwiązać te polecenia?
Odpowiedzi:
Powodem tego jest fakt, że bash rozszerza gwiazdkę do każdego pasującego pliku, tworząc bardzo długą linię poleceń.
Spróbuj tego:
Ostrzeżenie: jest to wyszukiwanie rekurencyjne, które również znajdzie (i usunie) pliki w podkatalogach. Dołączać
-f
do polecenia rm tylko jeśli jesteś pewien, że nie chcesz potwierdzenia.Możesz wykonać następujące czynności, aby polecenie nie było rekurencyjne:
Inną opcją jest użycie
-delete
flagi find :źródło
xargs
szczególności dzieli listę i wydaje w razie potrzeby kilka poleceń.-maxdepth 1
musi być pierwszym argumentem po ścieżce.-delete
flagę do usuwania znalezionych plików, a nawet jeśli nie, nadal uważane byłoby za lepszą praktykę-exec
wykonywania rm, zamiast wywoływania xargs (które są teraz 3 procesami i potokiem zamiast jednego procesu z-delete
lub 2 procesy z-exec
).dangerous (broken, exploitable, etc.)
jest dość niedorzeczna. Niewątpliwie należy zachować ostrożność podczas korzystaniaxargs
, ale nie jest to do końcaeval/evil
.-exec
wywoływaniarm
liczba procesów będzie wynosić 1 + liczba plików, chociaż liczba współbieżnych procesów z tego może wynosić 2 (być może funkcja find wykonałaby procesy rm jednocześnie). Liczba używanych procesówxargs
zostałaby radykalnie zmniejszona do 2 + n, gdzie n jest pewną liczbą procesów mniejszą niż liczba plików (powiedzmy liczbę plików / 10, chociaż prawdopodobnie więcej w zależności od długości ścieżek). Zakładając, że find wykonuje usuwanie bezpośrednio, użycie-delete
powinno być jedynym procesem, który zostałby wywołany.tl; dr
Jest to ograniczenie jądra dotyczące wielkości argumentu wiersza poleceń.
for
Zamiast tego użyj pętli.Geneza problemu
Jest to problem systemowy, związany
execve
iARG_MAX
stały. Jest mnóstwo dokumentacji na ten temat (patrz man execve , wiki debiana ).Zasadniczo rozszerzenie tworzy polecenie (z jego parametrami), które przekracza
ARG_MAX
limit. W jądrze2.6.23
limit został ustawiony na128 kB
. Ta stała została zwiększona i możesz uzyskać jej wartość, wykonując:Rozwiązanie: za pomocą
for
pętliUżyj
for
pętli, jak jest to zalecane w BashFAQ / 095, i nie ma limitu, z wyjątkiem pamięci RAM / pamięci:Uruchom na sucho, aby upewnić się, że usunie to, czego oczekujesz:
I wykonaj to:
Jest to również podejście przenośne, ponieważ glob ma silne i spójne zachowanie wśród powłok ( część specyfikacji POSIX ).
Uwaga: Jak zauważono w kilku komentarzach, jest to rzeczywiście wolniejsze, ale łatwiejsze w utrzymaniu, ponieważ może dostosować bardziej złożone scenariusze, np. Gdy chce się wykonać więcej niż jedną akcję.
Rozwiązanie: za pomocą
find
Jeśli nalegasz, możesz używać,
find
ale tak naprawdę nie używać xargs, ponieważ „jest niebezpieczny (uszkodzony, nadający się do wykorzystania itp.) Podczas odczytywania danych nie rozdzielonych znakiem NUL” :Użycie
-maxdepth 1 ... -delete
zamiast-exec rm {} +
pozwalafind
po prostu samodzielnie wykonać wymagane wywołania systemowe bez użycia zewnętrznego procesu, a tym samym szybciej (dzięki komentarzowi @chepner ).Bibliografia
źródło
for
pętli. Używałem jużfind
wcześniej, ale zawsze szukam, jak to zrobić, ponieważ cały czas zapominam o opcjach itp.for
wydaje się łatwiejsze do zapamiętania IMHOfor f in *; do rm "$f"; done
find -exec
Rozwiązaniem wydaje się być o wiele szybciej niżfor
pętli.4.15.0-1019-gcp
a dokładniej), a limit nadal wynosi 2097152. Co ciekawe, wyszukiwanie ARG_MAX na linux git repo daje wynik pokazujący ARG_MAX na 131702.find
ma-delete
działanie:źródło
xargs
odpowiedzi Dennisa działa zgodnie z przeznaczeniem.-exec
jest usunięcie kilku plików.-exec rm {} +
zrobiłby to samo, ale nadal wymaga uruchomienia co najmniej jednego procesu zewnętrznego.-delete
pozwalafind
po prostu samodzielnie wykonać wymagane wywołania systemowe bez użycia zewnętrznego opakowania.Inną odpowiedzią jest wymuszenie
xargs
przetwarzania poleceń w partiach. Na przykład dodelete
plików100
na raz,cd
do katalogu i uruchom to:echo *.pdf | xargs -n 100 rm
źródło
echo
jest wbudowana powłoka. Jeśli użyjesz poleceniaecho
, nadal będziesz mieć do czynienia z limitem argumentów programu.Lub możesz spróbować:
źródło
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Jeśli próbujesz usunąć bardzo dużą liczbę plików jednocześnie (dzisiaj usunąłem katalog z 485,000+), prawdopodobnie wystąpi ten błąd:
Problem polega na tym, że gdy coś wpiszesz
rm -rf *
,*
zostanie zastąpione listą każdego pasującego pliku, na przykład „rm -rf plik1 plik2 plik3 plik4” i tak dalej. Do przechowywania tej listy argumentów przydzielono stosunkowo mały bufor pamięci, a jeśli zostanie ona zapełniona, powłoka nie uruchomi programu.Aby obejść ten problem, wiele osób użyje polecenia find do znalezienia każdego pliku i przekaże je pojedynczo do polecenia „rm” w następujący sposób:
Mój problem polega na tym, że musiałem usunąć 500 000 plików i trwało to zbyt długo.
Natknąłem się na znacznie szybszy sposób usuwania plików - polecenie „find” ma wbudowaną flagę „-delete”! Oto, co wykorzystałem:
Korzystając z tej metody, usuwałem pliki z prędkością około 2000 plików na sekundę - znacznie szybciej!
Możesz także wyświetlać nazwy plików podczas ich usuwania:
… Lub nawet pokaż, ile plików zostanie usuniętych, a następnie określ, ile czasu zajmuje ich usunięcie:
źródło
sudo find . -type f -delete
usunąć około 485 tysięcy plików i pracował dla mnie. Zajęło to około 20 sekund.możesz spróbować:
EDYCJA: Komentarz ThiefMaster sugeruje, żebym nie ujawniał tak niebezpiecznej praktyki jedisom młodego shella, dlatego dodam bardziej „bezpieczniejszą” wersję (w celu zachowania rzeczy, gdy ktoś ma plik „-rf. ..Pdf”)
Po uruchomieniu powyższego, po prostu otwórz plik /tmp/dummy.sh w swoim ulubionym. edytor i sprawdzaj każdą linię pod kątem niebezpiecznych nazw plików, komentując je, jeśli zostaną znalezione.
Następnie skopiuj skrypt dummy.sh do działającego katalogu i uruchom go.
Wszystko to ze względów bezpieczeństwa.
źródło
-rf .. .pdf
-rf
ma pierwszeństwo przed-i
drugą wersją, więc druga wersja nie jest lepsza (bez ręcznej kontroli). I jest w zasadzie bezużyteczny do masowego usuwania, ponieważ monituje o każdy plik.Możesz użyć tablicy bash:
W ten sposób zostanie skasowany w partiach po 1000 plików na krok.
źródło
możesz użyć tego polecenia
źródło
Polecenie rm ma ograniczenie plików, które można jednocześnie usuwać.
Jedną z możliwości można je usunąć przy użyciu polecenia rm wielokrotnie w oparciu o wzorce plików, na przykład:
Możesz je również usunąć za pomocą polecenia find :
źródło
rm
nie ma takiego limitu liczby plików, które będzie przetwarzać (poza tym, żeargc
nie może być większy niżINT_MAX
). Jest to ograniczenie jądra do maksymalnego rozmiaru całej tablicy argumentów (dlatego długość nazw plików jest znacząca).Jeśli są to nazwy plików ze spacjami lub znakami specjalnymi, użyj:
To zdanie przeszukuje wszystkie pliki w bieżącym katalogu (-maxdepth 1) z rozszerzeniem pdf (-name „* .pdf”), a następnie usuwa każdy z nich (-exec rm "{}").
Wyrażenie {} zastępuje nazwę pliku i „{}” ustawia nazwę pliku jako ciąg znaków, zawierający spacje lub znaki specjalne.
źródło
-exec
to, że nie wywołujesz powłoki. Cytaty tutaj absolutnie nic pożytecznego. (Zapobiegają ekspansji symboli wieloznacznych i dzieleniu tokenów na łańcuchu w powłoce, w której wpisujesz to polecenie, ale łańcuch{}
nie zawiera żadnych białych znaków ani znaków wieloznacznych powłoki.)napotkałem ten sam problem podczas kopiowania katalogu źródłowego formularza do miejsca docelowego
katalog źródłowy miał pliki ~ 3 lakcs
użyłem cp z opcją -r i to zadziałało dla mnie
cp -r abc / def /
skopiuje wszystkie pliki z abc do def bez zbyt długiego ostrzeżenia o liście argumentów
źródło
Wypróbuj to także Jeśli chcesz usunąć pliki / foldery powyżej 30/90 dni (+) lub poniżej 30/90 dni (-) dni, możesz użyć poniższych poleceń ex
Np .: W przypadku 90 dni wykluczone powyżej po usunięciu plików / folderów w ciągu 90 dni, oznacza to 91,92 .... 100 dni
Przykład: w przypadku najnowszych plików 30-dniowych, które chcesz usunąć, użyj poniższego polecenia (-)
Jeśli chcesz odłożyć pliki na więcej niż 2 dni
Jeśli chcesz zobaczyć pliki / foldery tylko z ostatniego miesiąca. Dawny:
Ponad 30 dni więcej niż tylko lista plików / folderów Np .:
źródło
Dziwię się, że nie ma
ulimit
tu odpowiedzi. Za każdym razem, gdy mam ten problem, kończę tutaj lub tutaj . Rozumiem, że to rozwiązanie ma ograniczenia, aleulimit -s 65536
wydaje się, że często robi to dla mnie.źródło
Miałem ten sam problem z folderem pełnym tymczasowych obrazów, który rozwijał się z dnia na dzień, a to polecenie pomogło mi wyczyścić folder
Różnica w stosunku do innych poleceń to parametr mtime, który zajmie tylko pliki starsze niż X dni (w przykładzie 50 dni)
Używając tego wielokrotnie, zmniejszając się przy każdym wykonaniu zakresu dziennego, byłem w stanie usunąć wszystkie niepotrzebne pliki
źródło
Znam tylko sposób na obejście tego. Chodzi o to, aby wyeksportować tę listę plików pdf, które masz do pliku. Następnie podziel ten plik na kilka części. Następnie usuń pliki pdf wymienione w każdej części.
wc -l zlicza, ile linii zawiera list.txt. Kiedy masz pojęcie, jak długo to trwa, możesz zdecydować o podzieleniu go na pół, czwarte lub coś takiego. Używanie polecenia split -l Na przykład podziel go na 600 linii każdy.
spowoduje to utworzenie kilku plików o nazwach xaa, xab, xac i tak dalej, zależnie od sposobu podziału. Teraz, aby „zaimportować” każdą listę z tego pliku do polecenia rm, użyj tego:
Przepraszam za mój zły angielski.
źródło
pdf_format_sucks.docx
zostanie on również usunięty ... ;-) Powinieneś używać właściwego i dokładnego wyrażenia regularnego podczas wyszukiwania plików pdf.still_pdf_format_sucks.docx
zostaną usunięte. Kropka.
w".pdf"
wyrażeniu regularnym pasuje do dowolnego znaku. Sugerowałbym"[.]pdf$"
zamiast.pdf
.Kilka razy spotkałem się z tym problemem. Wiele rozwiązań uruchamia
rm
polecenie dla każdego pliku, który należy usunąć. Jest to bardzo nieefektywne:Skończyło się na tym, że napisałem skrypt Pythona, aby usunąć pliki na podstawie pierwszych 4 znaków w nazwie pliku:
To działało dla mnie bardzo dobrze. Udało mi się usunąć ponad 2 miliony plików tymczasowych w folderze w około 15 minut. Skomentowałem smołę z odrobiny kodu, aby każdy, kto ma minimalną lub żadną znajomość języka Python, mógł manipulować tym kodem.
źródło
I kolejny:
printf
jest wbudowaną powłoką i, o ile wiem, zawsze była taka. Biorąc pod uwagę, żeprintf
nie jest to polecenie powłoki (ale wbudowane), nie podlega „argument list too long ...
błąd krytyczny.Możemy więc bezpiecznie używać go z wzorcami globowania powłoki, takimi jak
*.[Pp][Dd][Ff]
, następnie przesyłamy dane wyjściowe do polecenia remove (rm
), przezxargs
co upewnia się, że pasuje ono do wystarczającej liczby nazw plików w wierszu poleceń, aby nie zawieśćrm
polecenia, które jest powłoką Komenda.\0
Wprintf
pełni rolę separatora null dla nazw plików wich są następnie przetwarzane przezxargs
polecenia, używając go (-0
) jako separatora, więcrm
nie zawieść, gdy istnieje spacji lub innych znaków specjalnych w nazwach plików.źródło
printf
nie jest wbudowana powłoka, będzie podlegać tym samym ograniczeniom.Możesz utworzyć folder tymczasowy, przenieść wszystkie pliki i podfoldery, które chcesz zachować, do folderu tymczasowego, a następnie usunąć stary folder i zmienić nazwę folderu tymczasowego na stary folder. Wypróbuj ten przykład, dopóki nie upewnisz się, że możesz to zrobić na żywo:
rm -r big_folder
usunie wszystkie pliki wbig_folder
nieważne ile. Musisz tylko bardzo uważać, aby najpierw mieć wszystkie pliki / foldery, które chcesz zachować, w tym przypadku tak byłofile1.pdf
źródło
Aby usunąć wszystko
*.pdf
z katalogu/path/to/dir_with_pdf_files/
Usuwanie określonych plików za
rsync
pomocą symboli wieloznacznych jest prawdopodobnie najszybszym rozwiązaniem w przypadku milionów plików. I zajmie się błędem, który otrzymujesz.(Krok opcjonalny): OSUSZANIE. Aby sprawdzić, co zostanie usunięte bez usuwania. `
. . .
Kliknij porady i wskazówki dotyczące rsync, aby uzyskać więcej hacków rsync
źródło
Odkryłem, że w przypadku bardzo dużych list plików (> 1e6) odpowiedzi te były zbyt wolne. Oto rozwiązanie wykorzystujące równoległe przetwarzanie w Pythonie. Wiem, wiem, to nie jest Linux ... ale nic innego tu nie działało.
(Oszczędzało mi to godzin)
źródło
Podobny problem napotkałem, gdy w aplikacji wypełniającej wszystkie i-węzły były miliony bezużytecznych plików dziennika. Uciekłem się do „zlokalizowania”, umieściłem wszystkie pliki „zlokalizowane” d w pliku tekstowym, a następnie usunąłem je jeden po drugim. Trochę to zajęło, ale wykonałem robotę!
źródło
locate
gdy wciąż masz miejsce na dysku.Trochę bezpieczniejsza wersja niż przy użyciu xargs, również nie rekurencyjna:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Filtrowanie naszych katalogów tutaj jest trochę niepotrzebne, ponieważ „rm” i tak go nie usunie, i można je usunąć dla uproszczenia, ale po co uruchamiać coś, co na pewno zwróci błąd?
źródło
ls
jest częstym antywzorzec projektowy, który zdecydowanie należy unikać, i dodaje kilka dodatkowych błędów tutaj. Togrep | grep
po prostu niezbyt elegancki.find
są dobre i dobrze udokumentowane tutaj i gdzie indziej. Zobacz np. Mywiki.wooledge.org, aby uzyskać więcej informacji na ten temat i pokrewne tematy.Używanie GNU równoległego (
sudo apt install parallel
) jest bardzo łatweUruchamia polecenia wielowątkowe, gdzie argumentem jest „{}”
Na przykład
ls /tmp/myfiles* | parallel 'rm {}'
źródło
ls
bezpośrednio do innych poleceń jest niebezpiecznym antypatternem - i fakt, że rozwinięcie symbolu wieloznacznego spowoduje taką samą awarię podczas wykonywania,ls
jak w przypadku oryginalnegorm
polecenia .parallel
sprawia, że niektórzy ludzie, którzy wolą unikać złożoności, są niewygodni - jeśli spojrzysz pod maską, jest to dość nieprzejrzyste. Zobacz wątek listy mailingowej na lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html między Stephane (jednym z greybeardów Unix i Linux StackExchange ) a Ole Tange (autor Parallel).xargs -P
również działa równolegle, ale robi to w prostszy, głupszy sposób z mniejszą liczbą ruchomych części, dzięki czemu jego zachowanie jest znacznie łatwiejsze do przewidzenia i uzasadnienia.Aby usunąć pierwsze 100 plików:
rm -rf 'ls | głowa -100 '
źródło
Poniższa opcja wydaje się prosta dla tego problemu. Mam te informacje z innego wątku, ale pomogło mi to.
Wystarczy uruchomić powyższe polecenie, a wykona zadanie.
źródło