Argumentliste zu langer Fehler für Befehle rm, cp, mv


629

Ich habe mehrere hundert PDFs in einem Verzeichnis unter UNIX. Die Namen der PDFs sind sehr lang (ca. 60 Zeichen).

Wenn ich versuche, alle PDFs zusammen mit dem folgenden Befehl zu löschen:

rm -f *.pdf

Ich erhalte folgende Fehlermeldung:

/bin/rm: cannot execute [Argument list too long]

Was ist die Lösung für diesen Fehler? Tritt dieser Fehler auch für mvund cpBefehle auf? Wenn ja, wie lösen Sie diese Befehle?


21
Sie könnten diesen Link nützlich finden
another.anon.coward


1
Auch dies kann relevant sein http://mywiki.wooledge.org/BashFAQ/095
Lorenzo Belli

4
@jww: Und ich habe so viele Jahre lang darüber nachgedacht, dass Bash unter "Software-Tools, die häufig von Programmierern verwendet werden" fällt - eine Kategorie, deren Fragen hier gestellt werden können!
Vicky

@Nik - Das Hinzufügen von "... in einem Skript" ist nicht zwingend. Wenn das Problem auf ein minimales, vollständiges und überprüfbares Beispiel reduziert ist , ist es nur eine Frage, wie ein Befehl ausgeführt wird. Ich entschuldige mich, wenn mir etwas Offensichtliches fehlt.
JWW

Antworten:


875

Der Grund dafür ist, dass bash das Sternchen tatsächlich auf jede übereinstimmende Datei erweitert und eine sehr lange Befehlszeile erzeugt.

Versuche dies:

find . -name "*.pdf" -print0 | xargs -0 rm

Warnung: Dies ist eine rekursive Suche, bei der auch Dateien in Unterverzeichnissen gefunden (und gelöscht) werden. Setzen Sie -fden Befehl rm nur ein, wenn Sie sicher sind, dass Sie keine Bestätigung wünschen.

Sie können Folgendes tun, um den Befehl nicht rekursiv zu machen:

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

Eine andere Option ist die Verwendung der -deleteFlagge von find :

find . -name "*.pdf" -delete

7
Nein, xargsteilt die Liste speziell auf und gibt bei Bedarf mehrere Befehle aus.
Tripleee

7
@ Tennis: -maxdepth 1muss das erste Argument nach dem Pfad sein.
Barton Chittenden

54
Find hat ein -deleteFlag zum Löschen der gefundenen Dateien, und selbst wenn dies nicht der Fall wäre, wäre es immer noch besser -exec, rm auszuführen, anstatt xargs aufzurufen (dies sind jetzt 3 Prozesse und eine Pipe anstelle eines einzelnen Prozesses mit -deleteoder 2 Prozesse mit -exec).
Scragar

3
@ ÉdouardLopez ... Aber dies liest eine durch NULL getrennte Eingabe. Und das Ganze dangerous (broken, exploitable, etc.)ist ziemlich lächerlich. Zweifellos sollten Sie bei der Verwendung vorsichtig sein xargs, aber es ist nicht ganz eval/evil.
Setzen Sie Monica bitte

4
@scragar Beim -execAufrufen rmbeträgt die Anzahl der Prozesse 1 + Anzahl der Dateien, obwohl die Anzahl der gleichzeitigen Prozesse daraus 2 betragen kann (möglicherweise würde find gleichzeitig rm-Prozesse ausführen). Die Anzahl der verwendeten Prozesse xargswürde drastisch auf 2 + n reduziert, wobei n eine Anzahl von Prozessen ist, die kleiner als die Anzahl der Dateien sind (z. B. Anzahl der Dateien / 10, obwohl dies wahrscheinlich mehr von der Länge der Pfade abhängt). Angenommen, find führt das Löschen direkt durch, -deletesollte using der einzige Prozess sein, der aufgerufen wird.
Neuralmer

396

tl; dr

Dies ist eine Kernelbeschränkung für die Größe des Befehlszeilenarguments. Verwenden Sie forstattdessen eine Schleife.

Ursprung des Problems

Dies ist ein Systemproblem, das mit execveund ARG_MAXkonstant ist. Es gibt eine Menge Dokumentation darüber (siehe man execve , Debians Wiki ).

Grundsätzlich erzeugt die Erweiterung einen Befehl (mit seinen Parametern), der den ARG_MAXGrenzwert überschreitet. Auf dem Kernel 2.6.23wurde das Limit auf gesetzt 128 kB. Diese Konstante wurde erhöht und Sie können ihren Wert erhalten, indem Sie Folgendes ausführen:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

Lösung: Verwenden von forLoop

Verwenden Sie eine forSchleife, wie sie in BashFAQ / 095 empfohlen wird, und es gibt keine Begrenzung außer für RAM / Speicherplatz:

Durch einen Trockenlauf wird sichergestellt, dass das, was Sie erwarten, gelöscht wird:

for f in *.pdf; do echo rm "$f"; done

Und führen Sie es aus:

for f in *.pdf; do rm "$f"; done

Dies ist auch ein portabler Ansatz, da Glob ein starkes und konsistentes Verhalten zwischen Shells aufweist ( Teil der POSIX-Spezifikation ).

Hinweis: Wie in mehreren Kommentaren erwähnt, ist dies zwar langsamer, aber wartbarer, da komplexere Szenarien angepasst werden können, z. B. wenn mehr als nur eine Aktion ausgeführt werden soll.

Lösung: Verwenden find

Wenn Sie darauf bestehen, können Sie xargs verwenden, findaber wirklich nicht, da es "gefährlich (kaputt, ausnutzbar usw.) beim Lesen von nicht durch NUL getrennten Eingaben ist" :

find . -maxdepth 1 -name '*.pdf' -delete 

Die Verwendung von -maxdepth 1 ... -deleteanstelle von -exec rm {} +ermöglicht findes, die erforderlichen Systemaufrufe einfach selbst auszuführen, ohne einen externen Prozess zu verwenden, und ist daher schneller (dank des Kommentars von @chepner ).

Verweise


31
Tolle Antwort, so sollten alle SO-Fragen beantwortet werden. Vielen Dank!
tommed

1
+1 für die Erwähnung der forSchleife. Ich habe es schon einmal benutzt find, aber ich schaue immer nach, wie es geht, da ich die Optionen usw. die ganze Zeit vergesse. forscheint leichter zu erinnern IMHO
Robert Dundon

3
Benutzte es als for f in *; do rm "$f"; doneArbeit als Zauber
abdul qayyum

3
Die find -execLösung scheint VIEL schneller zu sein als die forSchleife.
drei

2
Fünf Jahre später bei 4.15.0 ( 4.15.0-1019-gcpum genau zu sein) und das Limit liegt immer noch bei 2097152. Interessanterweise ergibt die Suche nach ARG_MAX im Linux Git Repo ein Ergebnis, das zeigt, dass ARG_MAX bei 131702 liegt.
Matt M.

181

findhat eine -deleteAktion:

find . -maxdepth 1 -name '*.pdf' -delete

4
Dies würde immer noch "Argumentliste zu lang" zurückgeben. Zumindest für mich. Die Verwendung xargsgemäß Dennis 'Antwort funktioniert wie beabsichtigt.
Sergio

7
Das klingt nach einem Fehler beim Finden.
ThiefMaster

3
@Sergio hatte das gleiche Problem, es wurde durch die fehlenden Anführungszeichen um das Namensmuster verursacht.
Luxian

argh, warum hat ein Tool zum Auffinden von Dingen überhaupt einen Schalter zum Löschen? Ist es wirklich nur ich, der es gelinde gesagt unnötig und auch gefährlich findet?
Mathreadler

2
@mathreadler Es wird die Tatsache angesprochen, dass ein häufiger Anwendungsfall darin -execbesteht, eine Reihe von Dateien zu entfernen. -exec rm {} +würde das gleiche tun, erfordert aber immer noch den Start mindestens eines externen Prozesses. -deleteermöglicht finddie einfache Ausführung der erforderlichen Systemaufrufe selbst ohne Verwendung eines externen Wrappers.
Chepper

21

Eine andere Antwort besteht darin, xargsdie Verarbeitung der Befehle in Stapeln zu erzwingen . Zum Beispiel zu deleteden Dateien 100gleichzeitig cdin das Verzeichnis und führen Sie Folgendes aus:

echo *.pdf | xargs -n 100 rm


4
Für das Löschen von Befehlen unter Linux, was eine Katastrophe sein kann, wenn Sie Ingenieur sind und einen Fehler eingegeben haben, halte ich es für das "sicherste und ich weiß, was los ist", das beste. Keine ausgefallenen Dinge, die Ihr Unternehmen in einer Minute zum Absturz bringen, wenn Sie einen Punkt verpassen.
Künstliche

1
Wie können wir dies zur Standarderweiterung für bestimmte Befehle machen? Es gibt viele "Standard" -Luxus-Befehle, bei denen bekannt ist, ob sie alle auf einmal benötigen oder nicht (wie "rm")
user1212212

1
Beachten Sie, dass dies nur dort funktioniert, wo echoeine Shell eingebaut ist. Wenn Sie den Befehl verwenden echo, stoßen Sie immer noch auf das Programmargumentlimit.
Toby Speight

14

Oder Sie können versuchen:

find . -name '*.pdf' -exec rm -f {} \;

Dadurch werden auch Dateien aus Unterverzeichnissen gelöscht. Wie kann man das verhindern?
Vicky

@ NikunjChauhan Add -maxdepth Option:find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Jon Lin

Ich kann die Option maxdepth nicht einfügen
Vicky

Diese Option kann gemäß der obigen Antwort von @ Dennis (die ausgewählte Antwort) eine reine Linux-Option sein.
Jvriesem

12

Wenn Sie versuchen, eine sehr große Anzahl von Dateien gleichzeitig zu löschen (ich habe heute ein Verzeichnis mit mehr als 485.000 gelöscht), wird wahrscheinlich dieser Fehler auftreten:

/bin/rm: Argument list too long.

Das Problem ist, dass beim Eingeben von etwas wie rm -rf *das *durch eine Liste aller übereinstimmenden Dateien ersetzt wird, z. B. "rm -rf Datei1 Datei2 Datei3 Datei4" und so weiter. Es gibt einen relativ kleinen Speicherpuffer zum Speichern dieser Liste von Argumenten, und wenn er voll ist, führt die Shell das Programm nicht aus.

Um dieses Problem zu umgehen, verwenden viele Benutzer den Befehl find, um jede Datei zu finden und sie einzeln wie folgt an den Befehl „rm“ zu übergeben:

find . -type f -exec rm -v {} \;

Mein Problem ist, dass ich 500.000 Dateien löschen musste und es viel zu lange dauerte.

Ich bin auf eine viel schnellere Methode zum Löschen von Dateien gestoßen - der Befehl "find" hat ein eingebautes "-delete" -Flag! Folgendes habe ich letztendlich verwendet:

find . -type f -delete

Mit dieser Methode löschte ich Dateien mit einer Geschwindigkeit von ungefähr 2000 Dateien / Sekunde - viel schneller!

Sie können die Dateinamen auch anzeigen, wenn Sie sie löschen:

find . -type f -print -delete

… Oder zeigen Sie sogar, wie viele Dateien gelöscht werden und wie lange es dauert, sie zu löschen:

root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real    0m3.660s
user    0m0.036s
sys     0m0.552s

Vielen Dank. Ich habe sudo find . -type f -deleteungefähr 485.000 Dateien gelöscht und es hat bei mir funktioniert. Dauerte ungefähr 20 Sekunden.
Nigel Alderton

11

Sie können dies versuchen:

for f in *.pdf
do
  rm $f
done

BEARBEITEN: ThiefMaster-Kommentar schlägt mir vor, solche gefährlichen Praktiken nicht an die Jedis junger Muscheln weiterzugeben, daher werde ich eine "sicherere" Version hinzufügen (um die Dinge zu bewahren, wenn jemand eine "-rf. ..Pdf" -Datei hat).

echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
   echo "rm -i $f" >> /tmp/dummy.sh
done

Nachdem Sie die oben genannten Schritte ausgeführt haben, öffnen Sie einfach die Datei /tmp/dummy.sh in Ihrem Favoriten. Bearbeiten Sie jede einzelne Zeile auf gefährliche Dateinamen und kommentieren Sie sie aus, wenn sie gefunden werden.

Kopieren Sie dann das Skript dummy.sh in Ihr Arbeitsverzeichnis und führen Sie es aus.

All dies aus Sicherheitsgründen.


5
Ich denke, das würde wirklich schöne Dinge mit einer Datei namens zB -rf .. .pdf
tun

Ja, aber im Allgemeinen sollte der Herausgeber des Befehls, wenn er in der Shell verwendet wird, einen Blick darauf werfen, was er tut :). Eigentlich bevorzuge ich es, in eine Datei umzuleiten und dann jede einzelne Zeile zu überprüfen.
BigMike

2
Dies zitiert nicht "$ f". Darüber sprach ThiefMaster. -rfhat Vorrang -i, daher ist Ihre 2. Version nicht besser (ohne manuelle Überprüfung). Und ist im Grunde genommen für das Massenlöschen nutzlos, da für jede Datei eine Aufforderung erfolgt.
Peter Cordes

7

Sie könnten ein Bash-Array verwenden:

files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
    rm -f "${files[@]:I:1000}"
done

Auf diese Weise werden Stapel von 1000 Dateien pro Schritt gelöscht.


2
Für eine große Anzahl von Dateien scheint dies deutlich schneller zu sein
James Tocknell


4

Der Befehl rm enthält eine Einschränkung von Dateien, die Sie gleichzeitig entfernen können.

Eine Möglichkeit, sie zu entfernen, indem Sie den Befehl rm mehrmals auf der Grundlage Ihrer Dateimuster verwenden, z.

rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf

Sie können sie auch über den Befehl find entfernen :

find . -name "*.pdf" -exec rm {} \;

3
Nein, rmdie Anzahl der zu verarbeitenden Dateien ist nicht begrenzt (außer dass argcsie nicht größer sein dürfen als INT_MAX). Dies ist die Beschränkung des Kernels auf die maximale Größe des gesamten Argumentarrays (aus diesem Grund ist die Länge der Dateinamen erheblich).
Toby Speight

3

Wenn es sich um Dateinamen mit Leerzeichen oder Sonderzeichen handelt, verwenden Sie:

find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;

Dieser Satz durchsucht alle Dateien im aktuellen Verzeichnis (-maxdepth 1) mit der Erweiterung pdf (-name '* .pdf') und löscht dann jede (-exec rm "{}").

Der Ausdruck {} ersetzt den Namen der Datei und "{}" legt den Dateinamen als Zeichenfolge fest, einschließlich Leerzeichen oder Sonderzeichen.


Während dieses Code-Snippet die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen , die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt! Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, und geben Sie an, welche Einschränkungen und Annahmen gelten.
Toby Speight

Der springende Punkt -execist, dass Sie keine Shell aufrufen. Die Zitate hier machen absolut nichts Nützliches. (Sie verhindern eine Platzhaltererweiterung und Token-Aufteilung für die Zeichenfolge in der Shell, in die Sie diesen Befehl{}
eingeben

2

Ich hatte das gleiche Problem beim Kopieren des Formularquellverzeichnisses zum Ziel

Quellverzeichnis hatte Dateien ~ 3 Lakcs

Ich habe CP mit Option -r verwendet und es hat bei mir funktioniert

cp -r abc / def /

Es kopiert alle Dateien von abc nach def, ohne zu lange vor der Argumentliste zu warnen


Ich weiß nicht, warum jemand dies abgelehnt hat, ohne dies zu kommentieren (das ist Politik, Leute!). Ich musste alle Dateien in einem Ordner löschen (die Frage bezieht sich nicht speziell auf PDFs, wohlgemerkt), und dafür funktioniert dieser Trick gut. Am Ende muss man nur den Ordner neu erstellen, der wann gelöscht wurde Ich habe "rm -R / path / to / folder" verwendet.
Thomas Tempelmann

1
Es funktioniert, weil er im Fall von OP * verwendet hat, das zu einer riesigen Liste von PDF-Dateien erweitert wurde. Wenn Sie ein Verzeichnis angeben, wird dies intern behandelt, sodass Sie sich nicht mit dem Problem von OP befassen müssen. Ich denke, es wurde aus diesem Grund abgelehnt. Es ist möglicherweise nicht für OP verwendbar, wenn er ein verschachteltes Verzeichnis oder andere Dateien (kein PDF) in seinem Verzeichnis hat
Alvein

2

Versuchen Sie dies auch Wenn Sie Dateien / Ordner über 30/90 Tage (+) oder unter 30/90 (-) Tagen löschen möchten, können Sie die folgenden ex-Befehle verwenden

Beispiel: Für 90-Tage-Ausschlüsse nach 90-tägigem Löschen von Dateien / Ordnern bedeutet dies 91,92 .... 100 Tage

find <path> -type f -mtime +90 -exec rm -rf {} \;

Beispiel: Verwenden Sie für nur die letzten 30-Tage-Dateien, die Sie löschen möchten, den folgenden Befehl (-).

find <path> -type f -mtime -30 -exec rm -rf {} \;

Wenn Sie die Dateien für mehr als 2 Tage Dateien giz möchten

find <path> -type f -mtime +2 -exec gzip {} \;

Wenn Sie die Dateien / Ordner nur aus dem letzten Monat sehen möchten. Ex:

find <path> -type f -mtime -30 -exec ls -lrt {} \;

Über 30 Tage mehr nur dann die Dateien / Ordner auflisten Beispiel:

find <path> -type f -mtime +30 -exec ls -lrt {} \;

find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} \;

2

Ich bin überrascht, dass es hier keine ulimitAntworten gibt. Jedes Mal, wenn ich dieses Problem habe, lande ich hier oder hier . Ich verstehe, dass diese Lösung Einschränkungen hat, aber ulimit -s 65536oft den Trick für mich zu tun scheint.


1

Ich hatte das gleiche Problem mit einem Ordner voller temporärer Bilder, der von Tag zu Tag größer wurde, und dieser Befehl half mir, den Ordner zu löschen

find . -name "*.png" -mtime +50 -exec rm {} \;

Der Unterschied zu den anderen Befehlen besteht im Parameter mtime, der nur die Dateien akzeptiert, die älter als X Tage sind (im Beispiel 50 Tage).

Durch mehrmaliges Verwenden konnte ich bei jeder Ausführung im Tagesbereich alle unnötigen Dateien entfernen


1

Ich kenne nur einen Weg, um das zu umgehen. Die Idee ist, diese Liste der PDF-Dateien, die Sie haben, in eine Datei zu exportieren. Teilen Sie diese Datei dann in mehrere Teile auf. Entfernen Sie dann die in den einzelnen Teilen aufgeführten PDF-Dateien.

ls | grep .pdf > list.txt
wc -l list.txt

wc -l zählt, wie viele Zeilen die list.txt enthält. Wenn Sie die Idee haben, wie lange es dauert, können Sie entscheiden, es in zwei Hälften, vier oder so zu teilen. Verwenden des Befehls split -l Teilen Sie ihn beispielsweise in jeweils 600 Zeilen auf.

split -l 600 list.txt

Dadurch werden einige Dateien mit den Namen xaa, xab, xac usw. erstellt. Dies hängt davon ab, wie Sie sie aufteilen. Verwenden Sie nun Folgendes, um jede Liste in diesen Dateien in den Befehl rm zu "importieren":

rm $(<xaa)
rm $(<xab)
rm $(<xac)

Entschuldigung für mein schlechtes Englisch.


5
Wenn Sie eine Datei mit dem Namen pdf_format_sucks.docxhaben, wird diese ebenfalls gelöscht ... ;-) Sie sollten beim Suchen nach PDF-Dateien den richtigen und genauen regulären Ausdruck verwenden.
FooF

1
Besser, still_pdf_format_sucks.docxwird aber gelöscht. Der Punkt .im ".pdf"regulären Ausdruck entspricht einem beliebigen Zeichen. Ich würde "[.]pdf$"stattdessen vorschlagen .pdf.
FooF

1

Ich bin ein paar Mal auf dieses Problem gestoßen. Viele der Lösungen führen den rmBefehl für jede einzelne Datei aus, die gelöscht werden muss. Das ist sehr ineffizient:

find . -name "*.pdf" -print0 | xargs -0 rm -rf

Am Ende habe ich ein Python-Skript geschrieben, um die Dateien basierend auf den ersten 4 Zeichen im Dateinamen zu löschen:

import os
filedir = '/tmp/' #The directory you wish to run rm on 
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist: 
    if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
        newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
    if 'tmp' in i:  #If statment to look for tmp in the filename/dirname
        print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
        os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell command
print ('DONE')

Das hat bei mir sehr gut funktioniert. Ich konnte in etwa 15 Minuten über 2 Millionen temporäre Dateien in einem Ordner löschen. Ich habe den Teer aus dem kleinen Code heraus kommentiert, damit jeder mit minimalen bis keinen Python-Kenntnissen diesen Code manipulieren kann.


1

Und noch einer:

cd  /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm

printfist eine Shell eingebaut, und soweit ich weiß, war es immer so. Da dies printfkein Shell-Befehl (sondern ein eingebauter) ist, kann es nicht zu einem argument list too long ...schwerwiegenden Fehler kommen.

Wir können es also sicher mit Shell-Globbing-Mustern verwenden, z. B. *.[Pp][Dd][Ff]dann leiten wir seine Ausgabe an den rmBefehl remove ( ) weiter, um xargssicherzustellen, dass genügend Dateinamen in die Befehlszeile passen, damit der rmBefehl, bei dem es sich um eine Shell handelt, nicht fehlschlägt Befehl.

Das \0in printfdient als Nulltrennzeichen für die Dateinamen, die dann per xargsBefehl verarbeitet werden , wobei it ( -0) als Trennzeichen verwendet wird. Es rmschlägt also nicht fehl, wenn die Dateinamen Leerzeichen oder andere Sonderzeichen enthalten.


1
Während dieses Code-Snippet die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen , die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt! Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, und geben Sie an, welche Einschränkungen und Annahmen gelten.
Toby Speight

Insbesondere wenn printfkeine Shell eingebaut ist, unterliegt sie derselben Einschränkung.
Toby Speight

0

Sie können einen temporären Ordner erstellen, alle Dateien und Unterordner, die Sie behalten möchten, in den temporären Ordner verschieben, dann den alten Ordner löschen und den temporären Ordner in den alten Ordner umbenennen. Versuchen Sie dieses Beispiel, bis Sie sicher sind, dass Sie es live ausführen können:

mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder

Das rm -r big_folderwird alle Dateien entfernen, big_folderegal wie viele. Sie müssen nur sehr vorsichtig sein, wenn Sie zuerst alle Dateien / Ordner haben, die Sie behalten möchten, in diesem Fall war es dasfile1.pdf


0

Alle *.pdfin einem Verzeichnis löschen/path/to/dir_with_pdf_files/

mkdir empty_dir        # Create temp empty dir

rsync -avh --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

Das Löschen bestimmter Dateien rsyncmithilfe eines Platzhalters ist wahrscheinlich die schnellste Lösung, wenn Sie Millionen von Dateien haben. Und es wird sich um Fehler kümmern, die Sie bekommen.


(Optionaler Schritt): DRY RUN. Um zu überprüfen, was gelöscht wird, ohne zu löschen. `

rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

. . .

Klicken Sie auf rsync-Tipps und -Tricks, um weitere rsync-Hacks zu erhalten


0

Ich fand, dass diese Antworten für extrem große Listen von Dateien (> 1e6) zu langsam waren. Hier ist eine Lösung mit paralleler Verarbeitung in Python. Ich weiß, ich weiß, das ist kein Linux ... aber sonst hat hier nichts funktioniert.

(Das hat mir Stunden gespart)

# delete files
import os as os
import glob
import multiprocessing as mp

directory = r'your/directory'
os.chdir(directory)


files_names = [i for i in glob.glob('*.{}'.format('pdf'))]

# report errors from pool

def callback_error(result):
    print('error', result)

# delete file using system command
def delete_files(file_name):
     os.system('rm -rf ' + file_name)

pool = mp.Pool(12)  
# or use pool = mp.Pool(mp.cpu_count())


if __name__ == '__main__':
    for file_name in files_names:
        print(file_name)
        pool.apply_async(delete_files,[file_name], error_callback=callback_error)

0

Ich hatte ein ähnliches Problem, als Millionen nutzloser Protokolldateien von einer Anwendung erstellt wurden, die alle Inodes füllte. Ich habe auf "Suchen" zurückgegriffen, alle "gefundenen" Dateien in eine Textdatei aufgenommen und sie dann einzeln entfernt. Hat eine Weile gedauert, aber den Job gemacht!


Dies ist ziemlich vage und erfordert, dass Sie locatezurück installiert haben, als Sie noch Platz auf Ihrer Festplatte hatten.
Tripleee

-2

Eine etwas sicherere Version als die Verwendung von xargs, auch nicht rekursiv: ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done

Das Filtern unserer Verzeichnisse hier ist etwas unnötig, da 'rm' es sowieso nicht löscht und es der Einfachheit halber entfernt werden kann. Aber warum etwas ausführen, das definitiv einen Fehler zurückgibt?


3
Dies ist überhaupt nicht sicher und funktioniert nicht mit Dateinamen mit Zeilenumbrüchen, um auf einen offensichtlichen Eckfall hinzuweisen. Das Parsenls ist ein häufiges Antimuster, das unbedingt vermieden werden sollte, und fügt hier eine Reihe zusätzlicher Fehler hinzu. Das grep | grepist einfach nicht sehr elegant.
Tripleee

Wie auch immer, es ist nicht so, dass dies ein neues und exotisches Problem ist, das eine komplexe Lösung erfordert. Die Antworten mit findsind gut und hier und anderswo gut dokumentiert. Weitere Informationen zu diesem und verwandten Themen finden Sie beispielsweise auf mywiki.wooledge.org .
Tripleee

-2

Die Verwendung von GNU parallel ( sudo apt install parallel) ist sehr einfach

Es führt die Befehle multithreaded aus, wobei '{}' das übergebene Argument ist

Z.B

ls /tmp/myfiles* | parallel 'rm {}'


Ich weiß es nicht, aber ich denke, es liegt daran, dass die lsdirekte Übergabe der Ausgabe an andere Befehle ein gefährliches Gegenmuster ist - das und die Tatsache, dass die Erweiterung des Platzhalters bei der Ausführung denselben Fehler verursacht lswie beim ursprünglichen rmBefehl .
Toby Speight

Informationen dazu finden Sie unter ParsingLs . Und paralleleinige Leute, die es vorziehen, Komplexität zu vermeiden, fühlen sich unwohl - wenn Sie unter die Haube schauen, ist es ziemlich undurchsichtig. Weitere Informationen finden Sie im Mailinglisten-Thread unter lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html zwischen Stephane (einem der Unix- und Linux- StackExchange-Graubärte) und Ole Tange (Parallel-Autor). xargs -Pparalellisiert auch, aber es macht es auf eine einfachere, dümmere Weise mit weniger beweglichen Teilen, wodurch sein Verhalten viel einfacher vorherzusagen und zu überlegen ist.
Charles Duffy

-2

Zum Entfernen der ersten 100 Dateien:

rm -rf 'ls | Kopf -100 '


2
Gefährlich (oder wenn Sie Backquotes wie offensichtlich beabsichtigt verwenden würden) - Wenn ein Dateiname Shell-Metazeichen, einschließlich Leerzeichen, enthält, stimmen die Ergebnisse nicht mit Ihren Absichten überein.
Toby Speight

-5

Die folgende Option scheint für dieses Problem einfach zu sein. Ich habe diese Informationen von einem anderen Thread erhalten, aber es hat mir geholfen.

for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
    cp "$file" /opt/sw/op-storage/
done

Führen Sie einfach den obigen Befehl aus und es wird die Aufgabe erledigen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.