ubuntuusers.de

Am Sonntag, 24.11, wird gegen 16 Uhr eine Inyoka-Version ausgerollt. Das Portal kann für ein paar Minuten nicht erreichbar sein.

Löschen via Papierkorb im Terminal - oder: trash-Kompatibilitätslayer für rm und rmdir

Status: Ungelöst | Ubuntu-Version: Ubuntu
Antworten |

Vanger

Anmeldungsdatum:
4. Juni 2009

Beiträge: 46

Hi Leute,

Warum überhaupt?
Manche kennen ja vielleicht dieses Problem: Man ist, der eine häufiger, der andere seltener (ich gehöre eher zu denen die es häufiger sind), im Terminal und möchte irgend eine Datei löschen. Also tippt man rm ein... Der Pfad zur Datei/zum Verzeichnis folgt... Und man vertippt sich. Blöderweise merkt man das erst nachdem man die Enter-Taste gedrückt hat und ärgert sich nun darüber, dass etwas verschwunden ist was nicht hätte verschwinden sollen. In jedem Fall ärgert man sich erst mal in Grund und Boden, danach holt man entweder die Backups raus oder versucht sich an Programmen wie extundelete. Beides kostet unnötig viel Zeit und beides hat so seine Tücken: Backups sind notorisch zu alt und solche Recovery-Tools finden notorisch nur die Dateien die man nicht sucht.

Mir ist das erst vor ein paar Wochen passiert: ich wollte "rm irgend/ein/pfad/dateien_mit_*" tippen, habe aber "rm irgend/ein/pfad/dateien_mit *" getippt - und schwupps waren alle Dateien in meinem Home-Verzeichnis weg. Ich hatte zwar aktuelle Backups mit denen ich die Dateien in der richtigen Version wiederherstellen konnte, blöderweise hatte ich ausgerechnet am vorherigen Tag eine wichtige Datei angelegt und erst am nächsten Tag wäre ein regelmäßiges Backup angestanden... Die Arbeit war also futsch. Gut, die meist angewandte Lösung ist in die .bashrc einen Alias mit "rm -I" zu legen: Dadurch wird man immer brav gefragt ob man die Aktion wirklich durchführen möchte - also zumindest wenn man rekursiv oder mehr als drei Parameter löschen möchte. Ich persönlich finde das recht störend, außerdem kenne ich mich: am Ende drücke ich automatisch y und die Schutzfunktion ist dahin...

Die Lösung: Der Papierkorb! Wie wär's mit dem trash-Kommando?
Dann ist mir eingefallen dass man den Papierkorb auch im Terminal nutzen kann. Der Befehl heißt trash (auf Desktop-System vorinstalliert, auf dem Server muss er nachinstalliert werden - imho auf Servern aber wenig sinnvoll). Löscht man etwas versehentlich holt man die Datei einfach wieder aus dem Papierkorb und fertig... Geleert wird der Papierkorb bei mir immer erst wenn der Speicher knapp wird, also sehr sehr selten - das stört also nicht. Schaut man sich trash --help an wird man aber enttäuscht... Da steht zwar etwas von Kompatibilität zu rm, die ist aber eher ein Witz: trash löscht nicht nur Dateien sondern immer auch Verzeichnisse, es wird immer rekursiv gelöscht und die manchmal sehr praktischen Interaktionsmöglichkeiten mit rm fehlen komplett.

Das Skript
Also habe ich mich hingesetzt und einen Kompatibilitäts-Layer geschrieben. Es werden alle Optionen von GNUs rm unterstützt - und zwar genau so wie auch bei rm, selbst die Ausgaben sind identisch (Verbose-Meldungen logischerweise nicht). Löscht man rekursiv wird der Befehl genau so dimensioniert, dass nicht die einzelnen Dateien im Papierkorb landen sondern möglichst die übergeordneten Verzeichnisse (wichtig wenn man interaktiv löscht oder das Flag --one-file-system gesetzt hat). Der Layer unterstützt auch das Löschen in nicht-interaktiven Shells, ist theoretisch also als kompletter Ersatz für rm geeignet. Das empfehle ich aber ausdrücklich nicht, ich warne sogar davor - der Papierkorb würde schnell überlaufen und die Performance einbrechen! Diese Unterstützung dient eher dazu, dass man einzelnen selbst geschriebenen Skripten erlauben kann den Layer zu nutzen. Noch ein Satz zur Performance: Der Befehl löscht die Dateien/Verzeichnisse nicht sondern verschiebt sie in den Papierkorb. Dieser ist zwar immer auf dem gleichen Dateisystem, geht also noch immer unmerklich schnell - dennoch, dass Verschieben eine geringere Performance hat als Löschen sollte klar sein. Der Layer ist in Bash geschrieben. Ich hatte zunächst nicht erwartet dass es so komplex wird, im Nachhinein wäre C++ sinnvoller gewesen - das ist mir aber blöderweise erst aufgefallen als eine Portierung noch mehr Aufwand bedeutet hätte.

Meine Anwendungsempfehlung ist das Skript unter /usr/local/bin/rmtrash abzulegen, ausführbar zu machen und in der .bashrc einen Alias für rm anzulegen. Schon wird euch in neu geöffneten Terminals der Befehl "rm --help" das Selbe wie "rmtrash --help" ausgeben. Zur Erinnerung: Die .bashrc gilt nur in von euch geöffneten Terminals. In Skripten (auch wenn es ein Bash-Skript ist und auch wenn es aus dem Terminal heraus gestartet wurde) wird rm wie gehabt zu /bin/rm führen. Sie gilt auch nicht in anderen Shells wie zsh. Um den Alias zu aktivieren einfach der ~/.bashrc (alternativ der ~/.bash_aliases) das hier hinzufügen:

1
alias rm='/usr/local/bin/rmtrash'

Das Skript findet ihr hier: https://github.com/PhrozenByte/rmtrash

rmdir
Übrigens: Das Gleiche gibt es auch für rmdir - also zum löschen leerer Verzeichnisse. Auch hier ist vollständige Kompatibilität zu GNUs rmdir gegeben und der Layer verhält sich auch exakt so. Der Ablauf zur Installation ist genauso wie auch bei rmtrash, das Skript findet ihr hier: https://github.com/PhrozenByte/rmtrash

Ich freue mich über Feedback - sowohl positive als auch konstruktive negative! Wenn ihr Fehler entdeckt: Immer nur her damit ☺

Viel Spaß damit und Grüße,
Rudi

Bearbeitet von redknight:

Links auf neues Ziel angepasst.

inos

Avatar von inos

Anmeldungsdatum:
10. Oktober 2006

Beiträge: 258

Wohnort: Dortmund

Guten Abend Rudi,

auch mir ist schon ähnliches passiert und so bin ich froh, mit deinem Programm so etwas in Zukunft verhindern zu können!

Herzlichen Dank dafür und für die Arbeit, die du investiert hast!

Viele Grüße

Martin

dAnjou

Avatar von dAnjou

Anmeldungsdatum:
8. Oktober 2007

Beiträge: 872

Wohnort: Berlin

Ups ... Beitrag nicht komplett gelesen, sorry.

Vanger

(Themenstarter)

Anmeldungsdatum:
4. Juni 2009

Beiträge: 46

Da hat sich noch ein kleiner Fehler eingeschlichen... Hat man das Flag --one-file-system gesetzt hat er trotzdem den Mountpoint eines anderen Dateisystems mit berücksichtigt, nur deren Inhalt nicht (ich nutze für die Dateiliste find, das macht das leider so). Soweit überhaupt nicht schlimm, hatte erst mal keine Auswirkungen, darum ist es mir wohl entgangen. Hat man aber die volle Interaktion eingeschaltet hat er gefragt ob man in den Mountpoint hinabsteigen will - verneinte man das wurden dann falsche Dateien übersprungen was zu einem gewissen Chaos geführt hat. Der Fehler wurde jetzt behoben, wie erwartet wird nach den Mountpoints erst gar nicht gefragt wenn das Flag --one-file-system gesetzt ist. Habe die neue Version 1.1 direkt hochgeladen, bitte aktualisieren.

edit: Auch für rmdirtrash liegt nun Version 1.1 vor. Die behebt keine Fehler, es wird nun lediglich bei Fehlermeldungen das Argument und nicht der absolute Pfad ausgegeben. Außerdem hab ich eine nicht nötige if-clause entfernt.

edit2: rmtrash liegt nun in Version 1.2 vor. Die behebt ebenfalls keinen Fehler, wie auch bei rm fragt er jetzt aber auch im Interaktivmodus "default" und "once" ob er in ein Verzeichnis hinabsteigen soll sofern dieses schreibgeschützt ist. Außerdem wird nun angegeben dass ein Verzeichnis schreibgeschützt ist soll dieses nach dem Hinabsteigen gelöscht werden weil es leer ist.

Lasall

Ehemalige
Avatar von Lasall

Anmeldungsdatum:
30. März 2010

Beiträge: 7723

Hi Vanger

was passiert bei Neuzeilen in Dateinamen? Verwende bei find zum Zaehlen der Ergibnisse etwas nach "-exec printf '.' \; | wc -c".

Gruss Lasall

Vanger

(Themenstarter)

Anmeldungsdatum:
4. Juni 2009

Beiträge: 46

Hi,

danke für die Meldung Lasall, an diese Problematik hatte ich noch überhaupt gar nicht gedacht. Habe ein Codereview durchgeführt mit dem ich glaube die Problematik gelöst zu haben, jedenfalls waren die Tests mit Files mit \n im Namen erfolgreich. Außerdem war im Code von rmtrash noch ein Fehler der bei manchen Verzeichnisstrukturen Probleme beim zurückrechnen des bestmöglichen Befehls verursacht hat.

Außerdem habe ich noch eine imho recht wichtige Funktion hinzugefügt: Aktuell darf jeder Benutzer Dateien in den Müll verschieben, insbesondere bei root ist das aber höchstwahrscheinlich nicht gewollt - die Dateien landen dann ja im Müll von root, dessen Inhalt wird dem Benutzer aber nirgends angezeigt und eher selten bis nie überprüft. In den meisten Fällen besteht kein Problem, führt sudo rm doch immer zu /bin/rm da die .bashrc nicht berücksichtigt wird (man sollte das aber im Hinterkopf behalten... Sprich: Vorsichtig sein!). Problematisch sind die interaktiven root-Shells. Während sudo -i (wie auch su sofern das noch jemand benutzt) noch keine Probleme macht da in diesem Fall die .bashrc von root geladen wird, ist sudo -s ziemlich problematisch - denn bei diesem Kommando gilt die .bashrc des ausführenden Benutzers. Für diesen Fall habe ich dem Skript die Parameter --forbid-root und --forbid-root-force hinzugefügt. Diese dienen nicht dazu sie beim normalen Aufruf zu verwenden sondern für die Alias-Definition in der .bashrc. Fügt man ersteres hinzu (also dass "alias rm='/usr/local/bin/rmtrash --forbid-root'" in der .bashrc steht) wird man gefragt ob man wirklich mit root trashen möchte - oder lieber das komplette Kommando an /bin/rm übergeben, sprich die Dateien sofort löschen möchte (bei einer nicht-interaktiven Shell wird abgebrochen; möchte man nichts von beidem drückt man wie immer Strg+c). Der Parameter --forbid-root-force erzwingt das sofortige Löschen, das Kommando wird also ohne Nachfrage direkt an /bin/rm übergeben (eine Meldung wird ausgegeben). Sprich: Option hinzufügen wenn gewünscht!

Noch etwas zur Performance: Ich habe die Performance noch mal eine Ecke nach oben geschraubt: Er braucht jetzt auf meinen 2 GHz Dual-Core-Notebook für 2.500 Dateien in Unterverzeichnissen verschachtelt nicht ganz 14 Sekunden. Das ist natürlich bedeutend schlechter als /bin/rm, aber nicht weiter verwunderlich... Anders als bei /bin/rm muss ein "optimaler Befehl" errechnet werden, das heißt die Dateiliste gleich 2x durchlaufen werden. /bin/rm dagegen kann die Dateien einfach simpel nacheinander abarbeiten. Außerdem ist der Layer nun mal in Bash geschrieben - wie gesagt, hätte ich von Anfang an gewusst dass es so komplex geworden wäre hätte ich ihn in C++ geschrieben... Was ich damit sagen will: Möchtet ihr mal richtig viel löschen soll das eh in den seltensten Fällen im Papierkorb landen, benutzt also lieber gleich /bin/rm, geht schneller. In dem Zusammenhang sei vielleicht auch erwähnt dass man getrost Strg+c drücken darf wenn der Befehl zu lange dauert - wirklich in den Papierkorb verschoben wird erst am Ende und das dauert meist <1 Sekunde. Die Gefahr dass ihr wie bei /bin/rm Verzeichnisse versehentlich "halb" löscht ist also sehr gering...

Version 1.3 von rmtrash und Version 1.2 von rmdirtrash sind wie immer schon hochgeladen, bitte aktualisieren.

Grüße,
Rudi

edit: Noch so ein kleiner Fehler der sich in rmdirtrash mit Parameter --parents eingeschlichen hat - \n in Verzeichnisnamen verursachten da noch Probleme... Version 1.3 von rmdirtrash ist hochgeladen, bitte aktualisieren.

Vanger

(Themenstarter)

Anmeldungsdatum:
4. Juni 2009

Beiträge: 46

Die Weiterentwicklung (wir sind inzwischen bei Version 1.7) findet inzwischen übrigens auf GitHub statt.

Antworten |