Ich habe mich gefragt, ob die Verwendung rm $(ls)
zum Löschen von Dateien (oder auch rm -r $(ls)
zum Löschen von Verzeichnissen) sicher ist. Weil auf allen Websites andere Möglichkeiten zur Verfügung stehen, obwohl dieser Befehl viel einfacher zu sein scheint als andere Befehle.
13
touch 'foo -r .. bar'
;rm $(ls)
; Wo ist mein Elternverzeichnis geblieben? Welche Alternativen sind für Sie noch komplizierter?rm *
Es ist viel einfacher zu tippen und darüber nachzudenken und sicherer (aber nicht absolut sicher; siehe Dennis 'Antwort).ls
diese von Implementierung zu Implementierung variieren können und daher nicht dem Standard entsprechen. Überlegen Sie sich je nach Bedarf Alternativen wiefind
undstat
. Sie solltenls
nur für den menschlichen Verzehr verwendet werden, niemals für die Verwendung durch andere Befehle oder in Skripten.Antworten:
Was soll das tun?
ls
listet Dateien im aktuellen Verzeichnis auf$(ls)
ersetzt die Ausgabe vonls
Orten, die als Argument fürrm
rm $(ls)
sollen alle Dateien im aktuellen Verzeichnis gelöscht werdenWas ist falsch mit diesem Bild ?
ls
Sonderzeichen im Dateinamen können nicht richtig behandelt werden. Unix-Benutzer empfahlen im Allgemeinen , unterschiedliche Ansätze zu verwenden . Ich habe das auch in einer verwandten Frage zum Zählen von Dateinamen gezeigt . Zum Beispiel:Wie in Denis 'Antwort richtig erwähnt, könnte ein Dateiname mit führenden Bindestrichen auch als Argument für
rm
after substitution interpretiert werden , was den Zweck des Entfernens des Dateinamens zunichte macht.Was funktioniert
Sie möchten Dateien im aktuellen Verzeichnis löschen. Also benutze glob
rm *
:Sie können den
find
Befehl verwenden. Dieses Tool wird häufig nicht nur für aktuelle Verzeichnisse empfohlen. Es kann den gesamten Verzeichnisbaum rekursiv durchlaufen und Dateien über verarbeiten-exec . . .{} \;
Python hat keine Probleme mit Sonderzeichen in Dateinamen, daher können wir dies auch verwenden (beachten Sie, dass dies nur für Dateien gilt, die Sie verwenden müssen
os.rmdir()
undos.path.isdir()
wenn Sie mit Verzeichnissen arbeiten möchten):Tatsächlich könnte der obige Befehl der
~/.bashrc
Kürze halber in eine Funktion oder einen Alias umgewandelt werden . Beispielsweise,Perl-Version davon wäre
quelle
"$(ls)"
Beispiel funktioniert nur, wenn sich nur eine Datei im Verzeichnis befindet. Sie können auch einfach die Tabulator-Vervollständigung verwenden, um den Dateinamen zu erweitern, da dies die einzige Vervollständigung ist.ls
dann :) Ich werde es herausarbeiten$(ls)
, um die Worttrennung zu deaktivieren, oder Sie lassen die Worttrennung zu (mit katastrophalen Ergebnissen). Die einzige saubere Möglichkeit, eine Liste mit mehreren Zeichenfolgen zu durchlaufen, ohne Daten als Code zu behandeln, besteht in der Verwendung von Array-Variablen oder\0
als Trennzeichen, aber die Shell selbst kann dies nicht. IstIFS=$'\n'
immer noch am wenigsten gefährlich, kann aber nicht mithaltenfind -print0 | xargs -0
. Odergrep -l --null
. Oder du vermeidest das ganze Problem mit Dingen wiefind -exec rm {} +
. (Beachten Sie+
, dass für jeden Aufruf von rm mehrere Argumente übergeben werden müssen; WEGE effizienter).IFS=$'\n'
wird auch in diesem Fall scheitern, da ich eine neue Zeile im Dateinamen habe, so dass Wordsplitting es als zwei Dateinamen anstelle von einem behandelt. Der seltsame Grund ist jedoch die Tatsache, dass mit der Standardeinstellung "IFS
Leerzeichen", "Tabulator", "Zeilenvorschub" und "Original"rm "$(ls)"
ebenfalls ein Fehler auftreten sollte. Der Dateiname sollte wie gesagt als zwei separate behandelt werden, was jedoch nicht der Fall war . Normalerweise benutze ichfind
mit-exec
oderfind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
Struktur mit Dateinamen umgehen. Oder man könnte es gebrauchenpython
, ich habe ein Beispiel hinzugefügt."$(ls)"
wird immer zu einem Argument erweitert, da die Anführungszeichen die Erweiterung von$(ls)
vor der Wortspaltung schützen . So wie sie beschützen"$foo"
.Nein, es ist nicht sicher und die häufig verwendete Alternative
rm *
ist nicht viel sicherer.Es gibt viele Probleme mit
rm $(ls)
. Wie andere bereits in ihren Antworten behandelt haben, wird die Ausgabe vonls
nach Zeichen aufgeteilt, die im internen Feldtrennzeichen vorhanden sind .Im besten Fall funktioniert es einfach nicht. Im schlimmsten Fall wollten Sie nur Dateien (aber keine Verzeichnisse) entfernen - oder selektiv einige Dateien mit entfernen
-i
-, aberc -rf
im aktuellen Verzeichnis befindet sich eine Datei mit dem Namen . Mal sehen was passiert.Der Befehl
rm -i $(ls)
sollte nur Dateien entfernen und vor dem Entfernen der einzelnen Dateien fragen, aber der Befehl, der letztendlich ausgeführt wurde, sollte gelesen werdenso tat es etwas ganz anderes.
Beachten Sie, dass dies
rm *
nur unwesentlich besser ist. Mit der Verzeichnisstruktur wie zuvor verhält es sich hier wie vorgesehen, aber wenn Sie eine Datei mit dem Namen haben-rf
, haben Sie immer noch Pech.Es gibt mehrere bessere Alternativen. Die einfachsten beinhalten nur rm und globbing.
Der Befehl
funktioniert genau wie vorgesehen, wobei
--
signalisiert wird, dass alles danach nicht als Option interpretiert werden soll.Dies ist seit über zwei Jahrzehnten Teil der POSIX-Utility-Syntaxrichtlinien. Es ist weit verbreitet, aber Sie sollten nicht erwarten, dass es überall vorhanden ist.
Der Befehl
bewirkt, dass der Glob anders erweitert wird und daher keine Unterstützung durch das aufgerufene Dienstprogramm erforderlich ist.
In meinem Beispiel von oben sehen Sie den Befehl, der letztendlich ausgeführt wird, indem das Echo vorangestellt wird .
Der Zeilenabstand
./
verhindert , dass rm versehentlich Dateinamen wie Optionen behandelt.quelle
rm
. +1touch 'foo -rf .. bar
. Ich glaube nicht, dass ein Angreifer höher als das übergeordnete Verzeichnis werden kann, es sei denn, wir können inls
der Ausgabe ein Pfadtrennzeichen erzeugen.rm: refusing to remove '.' or '..' directory: skipping '..'
beim Versuch, das übergeordnete Verzeichnis zu entfernen, etwas Ähnliches angezeigt .