it-swarm.com.de

Gibt es irgendwelche Nachteile bei der Verwendung von rm $ (ls) zum Löschen von Dateien?

Ich habe mich gefragt, ob die Verwendung von rm $(ls) zum Löschen von Dateien (oder von 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
posixKing

Was soll das tun?

  • ls listet Dateien im aktuellen Verzeichnis auf
  • $(ls) ersetzt die Ausgabe von ls und setzt diese als Argument für rm
  • Im Wesentlichen soll rm $(ls) alle Dateien im aktuellen Verzeichnis löschen

Was ist falsch mit diesem Bild ?

ls kann Sonderzeichen im Dateinamen nicht richtig verarbeiten. Unix-Benutzer im Allgemeinen empfohlen, unterschiedliche Ansätze zu verwenden . Ich habe auch gezeigt, dass in einer verwandte Frage zum Zählen von Dateinamen . Zum Beispiel:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

Wie in Denis 'Antwort richtig erwähnt, könnte ein Dateiname mit führenden Bindestrichen nach der Ersetzung als Argument für rm 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 *:

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

Sie können den Befehl find verwenden. Dieses Tool wird häufig nicht nur für aktuelle Verzeichnisse empfohlen - es kann rekursiv den gesamten Verzeichnisbaum durchlaufen und Dateien über -exec . . .{} \; bearbeiten.

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

Python hat keine Probleme mit Sonderzeichen in Dateinamen, daher können wir dies auch verwenden (beachten Sie, dass dies nur für Dateien gilt, Sie müssen os.rmdir() und os.path.isdir() verwenden, wenn Sie arbeiten möchten in Verzeichnissen):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

Tatsächlich könnte der obige Befehl der Kürze halber in ~/.bashrc in eine Funktion oder einen Alias ​​umgewandelt werden. Zum Beispiel,

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

Perl-Version davon wäre

Perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'
7

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 von ls in Zeichen aufgeteilt, die im internes Feldtrennzeichen vorhanden sind.

Im besten Fall funktioniert es einfach nicht. Im schlimmsten Fall wollten Sie nur Dateien (aber keine Verzeichnisse) entfernen - oder einige Dateien mit -i selektiv entfernen -, aber im aktuellen Verzeichnis befindet sich eine Datei mit dem Namen c -rf. Mal sehen was passiert.

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

Der Befehl rm -i $(ls) sollte nur Dateien entfernen und vor dem Entfernen jeder einzelnen nachfragen, aber der Befehl, der letztendlich ausgeführt wurde, sollte gelesen werden

rm -i a b c -rf

also tat es etwas ganz anderes.

Beachten Sie, dass 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 -rf haben, haben Sie immer noch Pech.

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

Es gibt mehrere bessere Alternativen. Die einfachsten sind nur rm und globbing.

  • Der Befehl

    rm -- *
    

    funktioniert genau wie vorgesehen, wobei -- signalisiert, dass alles danach nicht als Option interpretiert werden sollte.

    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

    rm ./*
    

    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 ein Echo vorangestellt wird.

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    Der führende ./ verhindert, dass rm versehentlich Dateinamen wie Optionen behandelt.

27
Dennis