Unix: So löschen Sie in einer Datei aufgelistete Dateien

88

Ich habe eine lange Textdatei mit einer Liste von Dateimasken, die ich löschen möchte

Beispiel:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

Ich muss sie löschen. Versucht rm `cat 1.txt` und es heißt, die Liste ist zu lang.

Ich habe diesen Befehl gefunden, aber wenn ich Ordner aus der Liste überprüfe, haben einige von ihnen noch Dateien. xargs rm <1.txtManueller rm-Aufruf entfernt Dateien aus solchen Ordnern, sodass keine Probleme mit Berechtigungen auftreten.

Alexander
quelle
8
Auch wenn es sechs Jahre später ist: Würde es Ihnen etwas ausmachen, eine der Antworten zu akzeptieren? Dies markiert die Frage als gelöst und hilft auch anderen Benutzern.
MERose

Antworten:

113

Dies ist nicht sehr effizient, funktioniert aber, wenn Sie Glob-Muster benötigen (wie in / var / www / *).

for f in $(cat 1.txt) ; do 
  rm "$f"
done

Wenn Sie keine Muster haben und sicher sind, dass Ihre Pfade in der Datei keine Leerzeichen oder andere seltsame Dinge enthalten, können Sie Xargs wie folgt verwenden:

xargs rm < 1.txt
nr
quelle
3
Was passiert mit der ersten Lösung (mit CAT), wenn der Pfad ein Leerzeichen enthält?
a.dibacco
57

Angenommen, die Liste der Dateien befindet sich in der Datei 1.txt, dann gehen Sie wie folgt vor :

xargs rm -r <1.txt

Die -rOption bewirkt eine Rekursion in alle in genannten Verzeichnisse 1.txt.

Wenn Dateien schreibgeschützt sind, verwenden Sie die -fOption, um das Löschen zu erzwingen:

xargs rm -rf <1.txt

Seien Sie vorsichtig mit dem Eingang zu jedem Werkzeug , die programmatische Deletion tut. Stellen Sie sicher, dass die in der Eingabedatei genannten Dateien wirklich gelöscht werden sollen. Seien Sie besonders vorsichtig bei scheinbar einfachen Tippfehlern. Wenn Sie beispielsweise ein Leerzeichen zwischen einer Datei und ihrem Suffix eingeben, werden zwei separate Dateinamen angezeigt:

file .txt

ist eigentlich zwei separate Dateien: fileund .txt.

Das mag nicht so gefährlich erscheinen, aber wenn der Tippfehler so etwas ist:

myoldfiles *

Dann , anstatt alle Dateien löschen , die mit beginnen myoldfiles, werden Sie am Ende zu löschen myoldfilesund alle nicht-Punkt-Dateien und Verzeichnisse im aktuellen Verzeichnis. Wahrscheinlich nicht das, was du wolltest.

aks
quelle
1
"myoldfiles /" oder "/ tmp" mit -rf noch katastrophaler. Beachten Sie das Leerzeichen neben dem "/".
Ray
22

Benutze das:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

Wenn Sie eine Glob-Erweiterung benötigen, können Sie das Zitieren weglassen $file:

IFS=""
while read -r file ; do rm -- $file ; done < delete.list

Aber seien Sie gewarnt, dass Dateinamen "problematischen" Inhalt enthalten können und ich die nicht zitierte Version verwenden würde. Stellen Sie sich dieses Muster in der Datei vor

*
*/*
*/*/*

Dies würde ziemlich viel aus dem aktuellen Verzeichnis löschen! Ich möchte Sie ermutigen, die Löschliste so vorzubereiten, dass keine Glob-Muster mehr erforderlich sind, und dann wie in meinem ersten Beispiel Zitate zu verwenden .

hek2mgl
quelle
2
Dies ist zur Zeit die einzige Antwort , die kümmert sich um alle /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesund als Bonus ist es POSIX und Werke auf GNU / Linux, MacOS und BSD.
dieser andere Typ
16

Sie können '\ n' verwenden, um das neue Zeilenzeichen als Trennzeichen zu definieren.

xargs -d '\n' rm < 1.txt

Seien Sie vorsichtig mit dem -rf, da es löschen kann, was Sie nicht möchten, wenn der 1.txt Pfade mit Leerzeichen enthält. Deshalb ist der neue Zeilenbegrenzer etwas sicherer.

Auf BSD-Systemen können Sie die Option -0 verwenden, um neue Zeilenzeichen als Trennzeichen wie folgt zu verwenden:

xargs -0 rm < 1.txt
Strahl
quelle
1
Unter OS X bringt mich dasxargs: illegal option -- d
waldyrious
Guter Punkt. Es scheint, dass es keine andere Option als -0unter OS X gibt.
Ray
2
xargs -I_ rm _funktioniert auch unter OS X :) siehe stackoverflow.com/a/39335402/266309
waldyrious
Wenn Sie BSD xargs verwenden (wo es keine gibt -d), können Sie zuerst Zeilenumbrüche in Nullen konvertieren:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog
13

Sie können diesen Einzeiler verwenden:

cat 1.txt | xargs echo rm | sh

Dies führt zu einer Shell-Erweiterung, wird jedoch rmmindestens so oft ausgeführt.

tgdavies
quelle
Solange eine Erweiterung nicht zu lang ist?
Douglas Leeder
1
Ein Glob könnte zwar eine zu lange Argumentliste erstellen. Sie können das -n <n>Argument hinzufügen xargs, um die Anzahl der an jeden RM übergebenen Argumente zu verringern. Dies schützt Sie jedoch nicht vor einem einzelnen Glob, der das Limit überschreitet.
Tgdavies
13

xargs -I{} sh -c 'rm {}' < 1.txtsollte tun was du willst. Seien Sie vorsichtig mit diesem Befehl, da ein falscher Eintrag in dieser Datei viele Probleme verursachen kann.

Diese Antwort wurde bearbeitet, nachdem @tdavies darauf hingewiesen hatte, dass das Original keine Shell-Erweiterung durchgeführt hat.

Mark Drago
quelle
Danke, aber keine Notwendigkeit, Ordner zu löschen, nur Dateien
Alexander
2
Die Globs werden nicht erweitert, da sie von der Shell nie "gesehen" werden.
Tgdavies
@tdavies wow - du hast recht. Dieser Befehl (wenn auch etwas hässlicher) wird funktionieren:xargs -I{} sh -c 'rm {}' < 1.txt
Mark Drago
4

In diesem speziellen Fall würde ich aufgrund der in anderen Antworten genannten Gefahren

  1. Bearbeiten Sie in z. B. Vim und :%s/\s/\\\0/g, wobei Sie alle Leerzeichen mit einem Backslash maskieren.

  2. Dann :%s/^/rm -rf /, das Voranstellen des Befehls. Mit -rSie müssen sich keine Sorgen machen Verzeichnisse haben aufgelistet , nachdem die darin enthaltenen Dateien, und mit -fihm wird nicht aufgrund von fehlenden Dateien oder doppelte Einträge beschweren.

  3. Führen Sie alle Befehle aus: $ source 1.txt

Evgeni Sergeev
quelle
Leerzeichen sind nicht die einzigen Zeichen, die maskiert werden müssen. In Dateinamen beliebt sind auch Klammern jeglicher Art, die zu unerwünschter Erweiterung führen können.
emk2203
4

cat 1.txt | xargs rm -f | bash Wenn Sie den Befehl ausführen, wird Folgendes nur für Dateien ausgeführt.

cat 1.txt | xargs rm -rf | bash Wenn Sie den Befehl ausführen, wird das folgende rekursive Verhalten ausgeführt.

Uzayr
quelle
1

Hier ist ein weiteres Schleifenbeispiel. Diese enthält auch eine 'if-Anweisung' als Beispiel für die Überprüfung, ob der Eintrag eine 'Datei' (oder beispielsweise ein 'Verzeichnis') ist:

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done
nthparameter
quelle
1

Um einen anderen Weg zu finden, können Sie auch einfach den folgenden Befehl verwenden

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )
QUentin
quelle
0

Hier können Sie Reihe von Ordnern aus verwenden deletelist.txt während einige Muster zu vermeiden und

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end
Chand Priyankara
quelle
0

Dadurch können Dateinamen Leerzeichen enthalten (reproduzierbares Beispiel).

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh
Ferroao
quelle
0

Falls jemand es bevorzugt sedund ohne Platzhaltererweiterung entfernt :

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

Erinnerung: Verwenden Sie absolute Pfadnamen in der Datei oder stellen Sie sicher, dass Sie sich im richtigen Verzeichnis befinden.

Und der Vollständigkeit halber das Gleiche mit awk:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

Die Platzhaltererweiterung funktioniert, wenn die einfachen Anführungszeichen entfernt werden. Dies ist jedoch gefährlich, wenn der Dateiname Leerzeichen enthält. Dies müsste Anführungszeichen um die Platzhalter hinzufügen.

Marco
quelle