Werden immer die Dateien aufgelistet, die rm entfernen wird?


33

Etwas , das ich glaube , ich sollte sicher wissen: Wenn ich ls <something>, wird rm <something>entfernen genau die gleichen Dateien , die lsangezeigt werden ? Gibt es Umstände, unter denen rmnicht angezeigte Dateien entfernt werden könnten ls? (Dies ist in der 18.04 Bash)

Edit: danke an alle die geantwortet haben. Ich denke, die vollständige Antwort ist eine Kombination aller Antworten, daher habe ich die am häufigsten gewählte Antwort als "die Antwort" akzeptiert.

Unerwartete Dinge, die ich dabei gelernt habe:

  • ls ist nicht so einfach, wie Sie vielleicht denken, wenn Sie mit seinen Argumenten umgehen
  • In einer einfachen Installation von Ubuntu, .bashrc Aliase ls
  • Benennen Sie Ihre Dateien nicht mit einem Bindestrich, da diese wie Befehlsargumente aussehen können, und die Benennung von one -r verlangt danach!

8
Ich bin etwas überrascht, dass rmkeine --dry-runFlagge hat ...
fkraiem

20
@Rinzwind Warum find -deletebesser als rm? Sie sagen "Deshalb" , aber mir ist völlig unklar, worauf sich das bezieht. Beachten Sie auch, dass Ihr findAufruf alle Dateien im aktuellen Verzeichnis rekursiv löscht , wobei rmnur die Dateien im unmittelbaren Verzeichnis gelöscht werden. Auch -name *ist ein No-Op. Alles in allem bin ich ziemlich verwirrt über Ihren Rat ...
Marcelm

3
@marcelm Ich denke, der Rat für die Verwendung findist, weil Sie es ausführen können, alle Dateien anzeigen und dann den gleichen Befehl mit ausführen können -delete. Da Sie bereits die Ergebnisse von gesehen haben find, sollte es keine Unklarheit darüber geben, was entfernt wird (ich würde gerne mehr Details dazu in Form einer Antwort hören)
Scribblemacher

5
@Scribblemacher "... Sie können es ausführen, alle Dateien-delete anzeigen und dann denselben Befehl mit " ausführen - Aber wie ist das besser als Ausführen ls <filespec>, gefolgt von rm <filespec>(dem das OP bereits weiß, wie es geht)?
Marcelm

12
@Rinzwind "Das löst die Antwort von choroba für den Moment, in dem eine Datei nach ls und vor rm erstellt wird." - Nein, das tut es nicht. Wenn Sie find ... -printzuerst ausführen , um zu bestätigen, welche Dateien gelöscht werden sollen, find ... -deletewerden die zwischen den beiden Befehlen erstellten Dateien trotzdem gelöscht. Wenn Sie beide -printund verwenden -delete, erhalten Sie keine Bestätigung, sondern nur einen nachträglichen Bericht darüber, was gelöscht wurde (und Sie können diesen auch verwenden rm -v).
Marcelm

Antworten:


40

Nun, beide lsund rmoperieren mit den Argumenten, die ihnen übergeben werden.

Diese Argumente können eine einfache Datei sein, so ls file.extund rm file.extarbeiten auf der gleichen Datei und das Ergebnis ist klar (Liste der Datei / Löschen der Datei).

Wenn argument stattdessen ein Verzeichnis ist, ls directorylistet es den Inhalt des Verzeichnisses auf, während rm directoryes nicht so funktioniert, wie es ist (dh rmohne Flags können Verzeichnisse nicht entfernt werden, wenn Sie dies tun rm -r directory, werden alle Dateien unter directory und das Verzeichnis selbst rekursiv gelöscht ).

Beachten Sie jedoch, dass Befehlszeilenargumente berücksichtigt werden können Shell-Erweiterung , sodass nicht immer gewährleistet ist, dass dieselben Argumente an beide Befehle übergeben werden, wenn sie Platzhalter, Variablen, Ausgaben von anderen Befehlen usw. enthalten.

Als extremes Beispiel denken Sie ls $(rand).txtund rm $(rand).txt, die Argumente sind "gleich", aber die Ergebnisse sind sehr unterschiedlich!


3
Betrachten Sie auch lsvs, rm *wo es "versteckte" (Punkt-) Dateien gibt, obwohl dies überhaupt kein fairer Vergleich ist, da ich nicht geschrieben habe ls *. Aber rmist für sich genommen bedeutungslos, so dass das Ganze wirklich Äpfel und Orangen sind. Wenn ich richtig verstanden habe, ist das der Kern Ihrer Antwort, also gute Arbeit :)
Leichtigkeitsrennen mit Monica

5
Ein weiterer Kommentar über lsvs rm -r: der Befehl ls <directory>wird im Verzeichnis nicht versteckte Dateien anzeigen, aber rm -r <directory> wird gelöscht werden, auch die versteckten Dateien.
Daniel Wagner

1
@LightnessRacesinOrbit lslistet sie nicht auf (sofern nicht anders angegeben ls -a) und rm *löscht sie nicht (sofern Sie dies nicht dotglobfestgelegt haben).
Hören Sie auf, Monica

20

Wenn Sie an etwas wie ls foo*.txtvs. denken rm foo*.txt, werden die gleichen Dateien angezeigt und entfernt. Die Shell erweitert den Glob und übergibt ihn an den betreffenden Befehl. Die Befehle wirken sich auf die aufgelisteten Dateien aus. Eine listet sie auf, eine entfernt sie.

Der offensichtliche Unterschied besteht darin, dass, wenn eine dieser Dateien ein Verzeichnis lswäre, der Inhalt aufgelistet rmwürde , dieser jedoch nicht entfernt werden könnte. Das ist in der Regel kein Problem, da rmsich weniger entfernen ließe als von gezeigt wurde ls.

Das Hauptproblem ist das Ausführen von ls *oder rm *in einem Verzeichnis, das Dateinamen enthält, die mit einem Bindestrich beginnen . Sie würden auf die Befehlszeilen der beiden Programme erweitert, als ob Sie sie selbst geschrieben hätten, und lswürden -r"umgekehrte Sortierreihenfolge" bedeuten , während dies eine rekursive Entfernung bedeuten rmwürde -r. Der Unterschied ist wichtig, wenn Sie Unterverzeichnisse haben, die mindestens zwei Ebenen tief sind. ( ls *Zeigt den Inhalt der Verzeichnisse der ersten Ebene an, aber rm -r *auch alles , was über die erste Unterebene hinausgeht.)

Um dies zu vermeiden, schreiben Sie zulässige Globs mit einem Anführungszeichen ./, um das aktuelle Verzeichnis anzuzeigen, und / oder setzen Sie ein --, um das Ende der Optionsverarbeitung vor dem Glob (dh rm ./*oder rm -- *) anzuzeigen .

Bei einem Glob wie *.txtist das eigentlich kein Problem, da der Punkt ein ungültiges Optionszeichen ist und einen Fehler verursacht (bis jemand die Hilfsprogramme erweitert, um eine Bedeutung dafür zu finden), aber es ist immer noch sicherer, das zu setzen./ dort zu platzieren.


Natürlich könnten Sie auch unterschiedliche Ergebnisse für die beiden Befehle erhalten, wenn Sie die Globbing-Optionen der Shell ändern oder Dateien zwischen den Befehlen erstellen / verschieben / entfernen, aber ich bezweifle, dass Sie einen dieser Fälle gemeint haben. (Der Umgang mit neuen / verschobenen Dateien wäre extrem umständlich und sicher.)


1
Vielen Dank. Dies scheint ein Problem mit der gesamten Befehlszeilensyntax hervorzuheben: Wenn Sie Dateien benennen, die mit einem Bindestrich beginnen, segeln Sie in gefährlichen Gewässern. Wer weiß, welche Befehle Sie in Zukunft verwenden werden, lange nachdem Sie die - Dateien vergessen haben?
B.Tanner

1
@ B.Tanner, ja. In gewisser Hinsicht besteht das Problem darin, dass die Befehlszeilenargumente nur einfache Zeichenfolgen sind. Wenn das System heute entworfen worden wäre, könnte es mehr Struktur enthalten, so dass das ausgeführte Programm wissen könnte, ob ein Argument ein Optionsflag sein sollte oder nicht. Es gibt auch andere Probleme, die von der sehr lockeren Struktur der Dateinamen herrühren. Es gibt einen sehr gründlichen Aufsatz darüber von Dwheeler , aber ich muss warnen, dass das Lesen schaden wird. (Entweder aus dem Detail oder aus der Schrecklichkeit, was schief gehen kann.)
Ilkkachu

3
Ich kann nicht widerstehen, Sie haben es mir verkauft, ich möchte es jetzt lesen, mit Erinnerungen an die Zeit, als ich es geschafft habe, am Ende vieler Dateinamen ein Wagenrücklaufzeichen zu erhalten (um zu sehen, ob ich es könnte)
Erstellen Sie

17

Konzentrieren wir uns, abgesehen vom Shell-Verhalten, nur auf das, was rmund lskönnen mit sich selbst umgehen. Mindestens ein Fall, in dem angezeigt lswird, was rmnicht entfernt werden kann, betrifft Verzeichnisberechtigungen und der andere - spezielle Verzeichnisse .und ...

Ordnerberechtigungen

rmDies ist eine Operation in einem Verzeichnis, da Sie durch das Entfernen einer Datei den Verzeichnisinhalt ändern (oder mit anderen Worten die Liste der Verzeichniseinträge, da das Verzeichnis nur eine Liste von Dateinamen und Inodes ist ). Dies bedeutet, dass Sie Schreibrechte für ein Verzeichnis benötigen. Auch wenn Sie der Eigentümer der Datei sind , können Sie ohne Verzeichnisberechtigungen keine Dateien entfernen. Das Gegenteil ist auch der Fall : Sie rmkönnen Dateien entfernen, die anderen gehören, wenn Sie Verzeichnisbesitzer sind.

So können Sie sehr gut gelesen haben und Ausführungsberechtigungen für ein Verzeichnis, das Sie das Verzeichnis und Sichten des Inhalts innerhalb von nur gut, zum Beispiel durchqueren können ls /bin/echo, aber Sie können nicht , rm /bin/echoes sei denn Sie sind der Besitzer/bin oder Ihre Privilegien erheben sudo.

Und Sie werden solche Fälle überall sehen. Hier ist ein solcher Fall: https://superuser.com/a/331124/418028


Spezielle Verzeichnisse '.' und '..'

Ein weiterer Sonderfall ist .und ..Verzeichnisse. Wenn du ls .oder tust ls .., zeigt es dir gerne den Inhalt an, aber rmes ist nicht erlaubt:

$ rm -rf .
rm: refusing to remove '.' or '..' directory: skipping '.'

15

Wenn Sie ls *und dann tippen rm *, werden möglicherweise mehr Dateien als lsangezeigt entfernt - sie wurden möglicherweise in dem winzigen Zeitintervall zwischen Ende lsund Anfang von erstellt rm.


1
Dies ist wahrscheinlich der Fall /tmp, wenn viele Anwendungen temporäre Dateien erstellen können, sodass dies in beiden Befehlen immer möglich ist *. Einige Anwendungen machen Dateien jedoch auch anonym, indem unlink()sie das Datei-Handle geöffnet lassen, sodass sie zwar angezeigt, ls *aber rm *möglicherweise nicht abgefangen werden.
Sergiy Kolodyazhnyy

1
@OrangeDog Sie verpassen den Punkt. Wir sprechen über den
Rennzustand

1
@OrangeDog Ich muss das überprüfen, da ich gerade telefoniere, aber der Punkt bleibt bestehen, obwohl *es einen Unterschied zwischen dem gibt, was lsangezeigt wird und dem, was ausgeführt wird rm, da sich die Auflistung der Verzeichnisinhalte zwischenzeitlich geändert hat.
Sergiy Kolodyazhnyy

1
Selbst wenn Sie nur einen Befehl ausführen, besteht eine Wettlaufsituation zwischen dem Erweitern und Löschen der Argumente.
Hören Sie auf, Monica

1
@OrangeDog Dem kann ich zustimmen. Da die Platzhaltererweiterung für vorhandene Dateinamen funktioniert, gibt es eine Race-Condition zwischen der Shell-Erweiterung des Platzhalters und einem Befehl, der ihn verarbeitet, sodass der ls *Dateiname angezeigt werden kann, der bereits weg ist.
Sergiy Kolodyazhnyy

9

ls *und rm *sind nicht dafür verantwortlich, den Glob zu erweitern - das erledigt die Shell, bevor sie ihn an den Befehl übergibt.

Das bedeutet, dass Sie mit der erweiterten Dateiliste jeden Befehl verwenden können - ich würde also etwas verwenden, das so wenig wie möglich funktioniert.

Ein besserer Weg, dies zu tun (oder zumindest einen anderen Weg), besteht darin, den Mittelsmann zu überspringen.

echo *zeigt Ihnen genau, was an Ihren rmBefehl weitergegeben werden würde.


2
Vielen Dank, ich mag die Idee, in diesem Szenario Echo anstelle von ls zu verwenden.
B.Tanner

3
Oder printf "%s\n" *um einen eindeutigen Überblick über Dateinamen mit Leerzeichen zu erhalten. (Oder %qstattdessen, um auch mit Zeilenumbrüchen und Steuerzeichen umzugehen, auf Kosten einer hässlicheren Ausgabe.)
ilkkachu

4

Wie wäre es mit:

$ mkdir what
$ cd what
$ mkdir -p huh/uhm ./-r
$ ls *
uhm
$ rm *
$ ls
-r
$ ls -R
.:
-r

./-r:

Grundsätzlich können Platzhalterzeichen, die auf Dinge erweitert werden, die mit beginnen -(oder manuell eingegebene Dinge, die mit beginnen, -aber ein bisschen mehr nach Schummeln aussehen), von lsund unterschiedlich interpretiert werden rm.


4

Es gibt Randfälle, in denen das, was lszeigt, nicht das ist, was rmentfernt wird. Ein ziemlich extremes, aber glücklicherweise lsharmloses Argument ist, wenn das von Ihnen übergebene Argument ein symbolischer Link zu einem Verzeichnis ist: Zeigt alle Dateien im verknüpften Verzeichnis an, rmentfernt den Symlink und lässt das ursprüngliche Verzeichnis und seinen Inhalt unverändert:

% ln -s $HOME some_link
% ls some_link    # Will display directory contents  
bin    lib    Desktop ...
% rm some_link
% ls $HOME
bin    lib    Desktop ...

1
Huh. ln -s $HOME some_link; ls some_linkAusgänge some_link@für mich, aber ich habe zu lsbefangen ls -F. Anscheinend wird -Fdas Verhalten dahingehend geändert, dass der Link angezeigt wird, anstatt ihn zu dereferenzieren. Das habe ich nicht erwartet.
Marcelm

Tatsächlich! Auch ls -lwenn beispielsweise der Link als Ziel und nicht das Ziel ausgewählt wird, muss es Möglichkeiten geben, den Link selbst zu überprüfen.
Alexis

1
Das Hinzufügen von Optionen zur Frage eröffnet zu viele Möglichkeiten - meine Antwort bezieht sich auf das unveränderte Verhalten von lsund rm.
Alexis

Wenn Sie , oder sagen ls some_link/,  wird das verknüpfte Verzeichnis aufgeführt, auch wenn Sie oder hinzufügen . Umgekehrt (sozusagen) sagt man, man solle sich ein Verzeichnis und nicht dessen Inhalt ansehen. vergleichen und . ls -H some_linkls -L some_link-F-l-dls -l /tmpls -ld /tmp
G-Man sagt, dass Monica

Natürlich können Sie Flags hinzufügen, die das Verhalten von ändern ls. Sie zeigen im Grunde, warum es sich nicht lohnt, Verhaltensweisen mit verschiedenen Flaggen aufzuzählen, um diese Frage zu beantworten ...
alexis

4

Wenn Sie dies nur lsanstelle von tun ls -a, rmkann yes versteckte Dateien entfernen, die Sie lsohne nicht gesehen haben -a.

Beispiel

Gemäß :

dir_test
├── .test
└── test2

ls dir_test : zeigt nur test2 an

ls -A dir_test : zeigt test2 + .test an

rm -r dir_test : entfernt alles (.test + test2)

Ich hoffe das wird dir helfen.


Können Sie ein Beispiel geben? Denn normalerweise rm *werden keine Punktedateien entfernt. Wenn ja, ls *werden sie auch angezeigt.
Marcelm

Nein, ls *keine versteckten Dateien anzeigen.
DevHugo

Aber ja, es ist ein bisschen verwirrt, ich habe einige Beispiele hinzugefügt.
DevHugo

1
ls -alistet ., .., .testund test2. Möglicherweise möchten Sie Ihr Beispiel ändern, um ls -Aalles außer . und ..(dh nur .testund test2) aufzulisten.
G-Man sagt, dass Monica

3

Es gibt bereits viele gute Antworten, aber ich möchte einen tieferen Einblick hinzufügen.

Stellen Sie sich die Frage: An wie viele Parameter werden beim lsSchreiben übergeben?

ls *

...? Beachten Sie, dass der lsBefehl den *as-Parameter nicht erhält , wenn Dateien vorhanden sind, *auf die erweitert werden kann. Stattdessen führt die Shell zuerst ein Globbing durch, bevor sie den Befehl aufruftls Befehl tatsächlich so viele Parameter erhält, wie Dateien vorhanden sind, die mit dem Globbing übereinstimmen. Um das Globen zu unterdrücken, geben Sie den Parameter an.

Dies gilt für jeden Befehl ein : echo *vs echo '*'.

Es gibt ein Skript, rufen Sie es countparams.shauf, um den Effekt zu testen. Es gibt an, wie viele Parameter übergeben wurden, und listet sie auf.

#!/bin/bash
echo "This script was given $# parameters."
arr=( "$@" )
for ((i=0;i<$#;i++)); do
        echo "Parameter $((i+1)): ${arr[$i]}"
done

Machen Sie es ausführbar und führen Sie es aus ./countparams.sh *. Lernen Sie aus seiner Leistung!


1

Der Glob wird beide Male auf dieselbe Weise erweitert, wenn der Verzeichnisinhalt zu diesen beiden unterschiedlichen Zeiten identisch ist.


Wenn Sie wirklich überprüfen möchten, was entfernt wird, verwenden Sie rm -i *.txt. Sie werden für jede Datei einzeln aufgefordert, bevor Sie versuchen, sie zu entfernen.

Dies ist gegen die Rennbedingungen garantiert sicher:
        ls *.txt/ Es wird eine neue Datei erstellt / rm *.txt
Sie werden von demselben Programm, das die Entfernung durchführt, zu jeder Datei aufgefordert.


Dies ist zu umständlich für den normalen Gebrauch, und wenn Sie Alias rmzu rm -i, Sie finden sich mit \rmoder rm -fziemlich oft. Zumindest ist zu erwähnen, dass es eine Lösung für die Rennbedingungen gibt. (Es ist sogar auf Nicht-GNU-Systeme übertragbar: POSIX rm(1)gibt die -iOption an .)

Eine andere Option wäre ein Bash-Array. to_remove=(*.txt)Bitten Sie dann den Benutzer, dies zu bestätigen (möglicherweise nachdem Sie dies getan haben ls -ld -- "${to_remove[@]}") rm -- "${to_remove[@]}". Die Glob-Erweiterung wird also nur einmal ausgeführt und die Liste wird wörtlich an übergeben rm.

Eine weitere praktisch verwendbare Option ist GNU rm -I( Manpage ), die zum Entfernen von mehr als 4 Elementen auffordert. (Zeigt Ihnen jedoch nicht die Liste, sondern nur die Gesamtsumme an.) Ich verwende sie alias rm='rm -I'auf meinem Desktop.

Es ist ein guter Schutz vor fettem Fingersatz mit einem zu viel passenden, halb getippten Muster. Die Verwendung von lsfirst ist jedoch in der Regel in einem eigenen Verzeichnis oder auf einem Einzelbenutzersystem sinnvoll, und wenn es keine Hintergrundprozesse gibt, die dort asynchron neue Dateien erstellen könnten. Geben Sie nicht rm -rf /foo/bar/bazvon links nach rechts ein , um Fett zu vermeiden . rm -rf /ist speziell verkleidet, aber rm -rf /usrnicht! Lassen Sie das -rfTeil weg oder beginnen Sie mit lsund fügen Sie das rm -rfTeil erst hinzu, nachdem Sie den Pfad eingegeben haben.

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.