Verhindern Sie, dass Benutzer versehentlich Leerzeichen zwischen rm und Platzhalter eingeben

29

Absicht:

rm -rf string*

Problem:

rm -rf string *

Der erste Fall ist eine legitime und gebräuchliche Verwendung von rm, ein kleiner Tippfehler kann im zweiten Fall viele Probleme verursachen. Gibt es eine einfache Möglichkeit zum intelligenten Schutz vor versehentlich nachgestellten oder führenden Platzhaltern?

Bobdole
quelle
8
Bei einer neueren und gut konfigurierten Shell ( zshoder bash) würde ich lieber die Tabulatortaste drücken (um die automatische Vervollständigung auszulösen), bevor
ich die Eingabetaste drücke
2
touch -- -ierstellt eine Datei -i, die rmals Parameter übergeben wird, -iwenn Sie ein Platzhalterzeichen in Ihre Argumente einfügen.
Wiedereinsetzung von Monica - M. Schröder am
@ MartinSchröder: Wenn du dich zufällig in dem Verzeichnis befindest, in dem die Datei existiert.
Bis auf weiteres angehalten.
@ MartinSchröder Das geht nur wenn du tippst rm *. Wenn Sie tippen rm name *, wird es zu erweitern rm name -i other names. -iwird nicht als Option verarbeitet, da es nicht vor den Dateinamen ist.
Barmar
1
Normalerweise macht ein Benutzer dies nur einmal.
Tedder42

Antworten:

37

Es DEBUGkönnte ein Trap geschrieben werden, um Befehle abzubrechen, die verdächtig aussehen. Folgendes oder ein ähnlicher Code kann zu Ihrem hinzugefügt werden ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Passen Sie die Logik nach Geschmack an.

(Eigentlich erwarte ich nicht, dass dieser Ansatz nützlich ist - zu viele Möglichkeiten, einen Befehl zerstörerisch durcheinander zu bringen, um sie einzeln testen zu können -, aber er bietet eine wörtliche Antwort auf die Frage.)

Charles Duffy
quelle
47

Es gibt keine Möglichkeit, ein System vollständig kugelsicher zu machen. Und das Hinzufügen von "Sind Sie sicher?" Aufforderungen zu Dingen sind sowohl kontraproduktiv als auch führen zu "Natürlich bin ich mir sicher." Knie-zuck-Reaktionen.

Ein Trick, den ich in den vergangenen Jahren in einem Buch aufgegriffen habe, ist, erst ls -R blah*dann zu tun, rm -fr blah* wenn die Auflistung, die auftaucht, genau das trifft, was ich wollte.

Es ist einfach genug, den lsBefehl zuerst auszuführen , dann zu löschen ls -Rund durch zu ersetzen rm -fr.

Die letzte Frage lautet: "Wenn die Informationen für Sie wertvoll waren, wo ist Ihr Backup?"

Killermist
quelle
4
^ls -R^rm -rf^
Anstelle des Aufwärtspfeils
FWIW, das ist ls -Res, was ich im Grunde die ganze Zeit mache, aber es ist zu diesem Zeitpunkt so instinktiv, dass es mir aus dem Kopf ging, als ich mich durch die Antwort formte. Also +1 dafür.
JakeGould
Dies hat auch den Vorteil, dass es nicht schadet, wenn Sie die Eingabetaste drücken oder die Maus drücken und etwas mit Zeilenumbrüchen einfügen. Ich cat > .loggebe Dinge manchmal in einer weniger effizienten Reihenfolge ein, um die Sicherheit zu erhöhen, z. B. gehe ich dann zurück und füge den Dateinamen vor dem ein .log. Also habe ich zu keinem Zeitpunkt > valuablefileauf der cmdline.
Peter Cordes
Ich benutze rm alias zu rm -i, so dass ich oft nur meinen rm-Befehl verfasse und dann ein \ an den Anfang der Zeile setze . ( \rmvermeidet Alias-Erweiterung für rm, da ein Teil des Wortes zitiert wurde). Wenn ich ein -roder brauchte -f, fange ich manchmal damit lsan rm, oder lass das -rfTeil einfach weg . (edit, wie bekommt man einen Backslash-Code-Formatierung? Bquote Bslash Bslash Bquote schlägt fehl.
Peter Cordes
8

Können Sie sich an die rmrfStelle von beispielsweise trainieren rm -rf?

In diesem Fall können Sie mit dieser Bash-Funktion sehen, was tatsächlich passieren würde, bevor Sie den Befehl bestätigen:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

Um diese Funktion dauerhaft zu aktivieren, fügen Sie diese Zeile der ~/.bashrcDatei auf jedem von Ihnen verwendeten Computer hinzu.

Vergleich mit dem allgemeinen rmAlias

Es ist üblich, einen Alias ​​zu definieren:

alias rm='rm -i'

Dies hat zwei Einschränkungen:

  1. Wenn Sie sich auf diesen Alias ​​verlassen, werden Sie einen Schock erleben, wenn Sie sich auf einem Computer befinden oder in einer Umgebung, in der er nicht vorhanden ist. Wenn Sie dagegen versuchen, rmrfauf einem Computer ohne diese Funktion zu laufen , wird ein harmloser Wert zurückgegeben command not found.

  2. Dieser Alias ​​ist in Ihrem Fall keine Hilfe, da die -fOption, die Sie in der Befehlszeile angeben, die -iOption im Alias überschreibt .

John1024
quelle
4
Keine schlechte Idee. Dies hängt jedoch davon ab, ob diese Funktion auf den von diesem Benutzer verwendeten Systemen installiert und verfügbar ist. Nehmen wir also an, sie melden sich für einige Arbeiten bei einem Remote-Server an und führen den falschen rm -rfBefehl aus. Was passiert dann? Das Erstellen von Pseudofunktionen wie diesen erschwert letztendlich nur eine einfache Lösung: Seien Sie nur vorsichtiger und verstehen Sie, was Berechtigungen sind.
JakeGould
4
@JakeGould Und verwende nicht rm -f, es sei denn, du brauchst es wirklich .
ein Lebenslauf vom
1
Warum sollte man sich die Mühe machen rmrf, anstatt nur eine Shell-Funktion zu erstellen rm, die nach den Argumenten sucht -roder -rfin diesem Fall eine spezielle Logik ausführt, und ansonsten direkt aufruft command rm "$@", um den echten rmBefehl aufzurufen ?
Charles Duffy
3
Sie verwenden einen anderen Namen, damit Sie sich nicht in den Fuß schießen, wenn Ihr Override nicht vorhanden ist. Und ich stimme mit @ MichaelKjörling überein, du brauchst nicht, -fwenn du nicht hast -i. Wenn -fSie diese Option deaktivieren, erhalten Sie eine zusätzliche Warnung, bevor Sie beispielsweise eine schreibgeschützte Datei entfernen.
Peter Cordes
6

Wenn ich in einer Situation bin , wo die falschen Dateien löschen eine wirklich große Sache ist, eines der Dinge , die ich getan habe , ist ein Papierkorb - Ordner zu machen, wie mkdir trashcan, und dann habe ich ein Skript , rmTrashcandas eine hat rm -rf trashcan/*oder rm -rf *oder ähnliches, geschrieben sehr sorgfältig und mehrmals überprüft.

Auf diese Weise liegt der Fehler bei einem mvBefehl und nicht bei einem rmBefehl , wenn ich einen Fehler mache . Sobald ich a mache lsund mir sicher bin , was genau ich lösche, rmTrashcanerledigt a die Drecksarbeit tatsächlich sicher.

Es war auch sehr praktisch für eine Situation, in der ich Backups löschen musste. Ich konnte mveinen ganzen Monat Backups in den Mülleimer, mvdie wenigen , die ich behalten wollte (1. des Monats, 15. des Monats), wieder in die Backups, dann rmTranshcanden Rest. Es ist schwierig, einen ähnlichen Befehl rmalleine auszuführen, und auf diese Weise können lsdie Backups sicher sein, welche Dateien ich zurücklasse (anstatt nur die Dateien aufzulisten, die ich löschen möchte).

Cort Ammon - Setzen Sie Monica wieder ein
quelle
4

Anstatt sich mit zwei Befehlen ( lsund rm) zu beschäftigen, ist die Verwendung meines Erachtens einfacher und einfacher find:

find . -maxdepth 1 -name "string*" -delete

Wenn Sie versehentlich tippen "string *", werden die Dateien mit dem Namen string charsund gelöscht string letters(was Sie sowieso wollten), es werden jedoch nicht alle Dateien wie *in einer Shell abgerufen.

Sie können auch -deletedas Feld weglassen, um zu sehen, welche Dateien gelöscht werden sollen, dann den Pfeil nach oben drücken und -deleteeinfacher tippen als tippen ^ls -R^rm -rfoder anderen Unsinn.

Kindermädchen
quelle
A findführt eine verschachtelte Suche nach Dateien durch, die den in der Befehlszeile deklarierten expliziten Parametern entsprechen. Ich denke, das verfehlt die Marke. Ich könnte mich jedoch irren.
Killermist
3

Gibt es eine einfache Möglichkeit zum intelligenten Schutz vor versehentlich nachgestellten oder führenden Platzhaltern?

Nicht wirklich. In einer anderen Antwort wird vorgeschlagen, vor dem Ausführen einer Aufgabe einen benutzerdefinierten Befehl zum Hinzufügen einer Eingabeaufforderung zu erstellen. Das Problem bei diesem benutzerdefinierten Befehl ist jedoch, dass er bewusst auf den Systemen installiert werden muss, an denen Sie arbeiten. Und selbst wenn es installiert ist, ist das Problem, dass Ihr Reflex, den Sie treffen müssen y, um die Aufgabe zu erledigen, ins Spiel kommen könnte.

Das bedeutet, dass dies alles ein Problem der Benutzeroberfläche ist, auch wenn es sich um eine Text- / Befehlszeilenebene handelt. Wie viele Sicherheitsnetze erwarten Sie, um Sie davor zu schützen, etwas zu tun, das Sie nicht tun sollten? Es ist wie mit einer Schere: Wer ist schuld, wenn Sie nachlässig sind und Ihre Hand abrutschen und schneiden, während Sie beabsichtigen, Stoff oder Papier zu schneiden? Oder sogar Ampeln und Stoppschilder: Es gibt wirklich nichts, was einen Fahrer davon abhält, eine Ampel zu fahren oder Verkehrszeichen zu ignorieren, außer ein scharfes Bewusstsein dafür, was passieren könnte, wenn er sich auf ein derart riskantes Verhalten einlässt.

Die beste und realistischste Lösung sind jedoch die Systemberechtigungen für Benutzer und Gruppen. Das ist das beste / einzige echte Sicherheitsnetz, um einen Benutzer vor sich selbst zu schützen.

Wenn Sie an einem System arbeiten, auf das nur Sie zugreifen, könnte es sein, dass Sie zu allem versucht sind chmod 777, aber so wird ein rationales System nicht eingerichtet. Stattdessen sollten die Berechtigungen 755für alle Verzeichnisse und 644für alle nicht ausführbaren Dateien gleich sein. Ausführbare Dateien sollten 755mindestens vorhanden sein, aber möglicherweise auch dann, 744wenn Sie nur möchten, dass andere die Dateien lesen, aber nicht ausführen.

JakeGould
quelle
2

Versuchen Sie, Ihren anfänglichen rmBefehl ohne das -fFlag, aber mit -iso zu verfassen , dass rmSie für jede zu löschende Datei aufgefordert werden. Bei kleinen rekursiven Löschvorgängen können Sie die yTaste gedrückt halten, sobald Sie sicher sind, dass der Befehl richtig eingegeben wurde. Für große Deletionen, können Sie den Vorgang abbrechen, und die Geschichte Verwendung Command sorgfältig die ändern -izu ein -f.

Nevin Williams
quelle
Sie müssen tatsächlich y[RETURN]jede Datei drücken , es gibt nichts, was Sie mit GNU rm festhalten können. Wenn -iSie den Befehl richtig eingegeben haben, müssen Sie nur noch das bearbeiten . Dann erhalten Sie eine Eingabeaufforderung nur für eine schreibgeschützte Datei und möglicherweise für andere Dinge.
Peter Cordes
1
Verwenden rm -ISie einfach, damit es nur einmal und nur für potenziell gefährliche Löschvorgänge (dh von vielen Dateien) auffordert.
Nick Matteo
1
In weniger konstruktiven Foren wäre meine Antwort etwa so gewesen: "Wenn Sie so schlecht tippen / korrigieren, haben Sie nichts damit zu tun, 'rm -rf' mit Platzhaltern zu verwenden." Ich wusste nichts von dem -I-Schalter ... muss vor <20 Jahren eingeführt worden sein; Das letzte Mal, als ich "man rm" gemacht habe. :)
Nevin Williams
2

rm muss -iund -Iflags vor jedem entfernen bestätigen. In der Vergangenheit haben einige Distributionen diese standardmäßig aktiviert. Das ist eine schreckliche Idee. Geben Sie dem Benutzer zu viele Bestätigungsdialogfelder für den normalen Betrieb, und er beginnt, diese gewöhnlich zu bestätigen. Dies verlagert die Forderung nach "Vorsicht" (immer eine rote Fahne) auf einen neuen und nervigeren Dialog. "Ja. Ja. Ja. Ja! JA! Verdammt, dummer Computer, lösche einfach die Dateien. Dies ist das "Ja, aber ich meinte nein" -Dialogproblem. Diese Antwort bietet eine visuelle Erklärung, warum Bestätigungsdialogfelder zum falschen Zeitpunkt angezeigt werden.

Die Art von Fehler, die Sie beschreiben, ist ein Ausrutscher , "die Ausführung einer Handlung, die nicht das war, was beabsichtigt war". Der Benutzer erkennt den Fehler normalerweise sofort und weiß genau, wie er behoben werden kann. Leider gibt Unix dem Benutzer nicht die Möglichkeit, rm löscht die Datei sofort. Jedes andere Betriebssystem löst dieses Problem, indem es zulässt, dass Löschvorgänge mithilfe des Papierkorbs zumindest für kurze Zeit rückgängig gemacht werden.

Es gibt verschiedene Müllsysteme für Unix, und diese Antwort steckt voller Vorschläge .

Die Frage ist nach Alias ​​rm oder nicht nach Alias ​​rm. Vorteile des Aliasing von rm ...

  1. Man kann nicht vergessen, die Alternative rm zu nutzen.

Nachteile für das Aliasing von rm ...

  1. Sie könnten sich auf Systeme verlassen, die es nicht haben.
  2. Kann Probleme verursachen, wenn die Festplatte fast voll ist.
  3. Benötigen Sie eine Infrastruktur, um den Papierkorb regelmäßig zu leeren.
  4. Darauf achten, dass das erwartete Verhalten von rm in Programmen nicht beeinträchtigt wird.
  5. Kann rm nicht vollständig emulieren.

Wenn Sie dem ersten Argument zu weit folgen, verwenden Sie vi (nicht vim, vi), csh (nicht tcsh, csh) und andere veraltete Dienstprogramme, da diese allgemein verfügbar sind. Dennoch besteht die Gefahr einer Überanpassung Ihrer Umgebung. Ich nehme meine Dienstprogramme lieber mit und mache es mir so einfach wie möglich. YMMV.

Zwei und drei sind technische Probleme. Sie können mit einem cleveren Schnitter-Job gelöst werden, der die Größe des Mülls überprüft und die Dinge regelmäßig aufräumt, ähnlich wie bei einem billigen . Dies kann ein Cron-Job sein, oder eine cleverere Version kann die verschiedenen Dateisystem-Ereignisinfrastrukturen nutzen, die auf vielen Desktop-Linux-Distributionen verfügbar sind. Dies ist nicht einfach und noch schwieriger effizient zu erledigen. Es ist besser, ein vorhandenes System zu finden, als zu versuchen, ein eigenes zu erstellen.

Das vierte Problem kann behoben werden, indem Sie Ihren neuen rm zu einem Shell-Alias ​​machen alias rm='trash'. Dann hat dies keine Auswirkungen auf Programme.

Das fünfte Problem überlasse ich dem Leser. RM hat nicht viele Schalter.

Schwern
quelle
Ich bin auf voreingenommen rm -i, aber ich benutze \rmes oft , um ein voreingenommenes Verhalten zu bekommen. Ich rm -itippe jedes Mal, wenn ich NEIN zu einem der Argumente sagen will. Ich starte den Befehl manchmal lsals Befehl und gebe dann erst dann den \ rm ein, wenn ich fertig bin. Also gibt es keinen Weg , ich versehentlich Rückkehr treffen kann auf rm -rf /statt/.../file
Peter Cordes
rm -Ioder rm --interactive=onceist weit, weit weniger ärgerlich als rm -iund fängt immer noch etwas Gefährliches (es wird nur angezeigt, wenn es mehr als 3 Dateien gibt oder wenn es rekursiv ist und nur EINMAL anstelle von FÜR JEDE DATEI.)
Nick Matteo
@Kundor Ja, und es ändert nichts an der Gleichung. Es macht es wahrscheinlich wahrscheinlicher, dass der Benutzer es ignoriert. Der Benutzer hat ein Ziel: Sachen löschen. Die Eingabeaufforderung lautet "Sind Sie sicher, dass Sie den Inhalt löschen möchten, den Sie gerade gelöscht haben?" Der Benutzer ist immer noch auf das Ziel fixiert, Dinge zu löschen, nicht zu überprüfen, was gelöscht werden soll, und sagt daher "Ja", ohne darüber nachzudenken. -ikann dem Benutzer Zeit geben, Ziele zu ändern. Diese Antwort auf eine verwandte Frage zeigt alles auf.
Schwern,
@Schwern: aber niemand kann möglicherweise rm -ilänger als 30 Sekunden damit leben, ohne es auszuschalten. Während rm -Inur fordert, wenn es wahrscheinlich ist, dass Sie vermasselt haben; Die Aufforderung kommt nur für große Löschungen. Wenn Sie versucht haben, ein paar Dinge zu löschen, und die Aufforderung angezeigt wird, sind Sie überrascht und stellen fest, dass Sie versehentlich "foo *" eingegeben haben.
Nick Matteo
@Kundor Das Löschen von mehr als drei Dateien und das rekursive Löschen (die Bestätigung ist aufgrund der -rfsoeben entdeckten Gewohnheit deaktiviert ) sind schlechte Proxys, um einen wahrscheinlichen Fehler zu erkennen. Das Löschen eines Unterverzeichnisses ist wahrscheinlich kein Problem. Die Meldung hilft nicht weiter, da sie nur bestätigt, was der Benutzer gesagt hat, ohne nützliche Informationen an einem Punkt hinzuzufügen, an dem der Benutzer nicht nachprüfen möchte. "rm: 1 Argument rekursiv entfernen?" "Ja, lösche das Verzeichnis, ich habe dir gerade gesagt, dass du das machen sollst! ... warte, welches Verzeichnis war das? CRAP !!!"
Schwern
2

Ich bringe jedem das !$letzte Argument im letzten Befehlstrick bei:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

Dies ermöglicht eine Überprüfung der Platzhaltererweiterung und anschließend die Verwendung des exakt gleichen Glob-Musters, ohne die Möglichkeit, ein Leerzeichen vor dem einzufügen *.

Außerdem schlage ich vor, dass Benutzer niemals ein Platzhaltermuster ausschneiden und in eine möglicherweise destruktive Befehlszeile einfügen. Denn in meinen eigenen Händen war das ein Problem :)

Ein Techniker in meinem Labor hat diesen Fehler letzte Woche gemacht (3 Monate Arbeit) - und ja, wir hatten ein Backup (1 Tag im Rückstand).

kael
quelle
0

Jeder scheint zu sagen: "Seien Sie vorsichtiger", "Machen Sie keine Alias- / Bestätigungsaufforderung, weil Sie sich daran gewöhnen, dass Sie sich nicht richtig darum kümmern".

Cool und alles. Ich meine, ich denke nicht, dass Sie einen Alias ​​für machen sollten rm(noch rmrf, da Sie das leicht vermasseln und den echten Befehl eingeben könnten).

Aber warum können Sie nicht einen Alias ​​/ ein Skript erstellen und ihn / es sagen removeund nur ein Argument (z. B. $ 1) eingeben? Der Platzhalter sollte $ 2 sein, da es sich um ein versehentliches Leerzeichen handelt (amiright?) Und daher wird Ihrem Skript / Wrapper / Alias ​​nicht der zweite Platz zugewiesen. Ja, Sie können jeweils nur einen Satz von Löschvorgängen (mit Platzhalterzeichen) ausführen, aber das ist der Preis, den Sie bezahlen würden.

Wenn ich etwas Nettes schreibe, kann ich mir die Anzahl der zu löschenden Dateien und Verzeichnisse sowie die Gesamtgröße der gelöschten Dateien anzeigen lassen und danach eine Bestätigung anfordern, aber dies kann Ihren Datenfluss beeinträchtigen. Vielleicht machen Sie das zu einer Flaggenoption remove? (-ich). Möglicherweise möchten Sie auch $ 1 überprüfen, um festzustellen, ob es sich nur um einen einzelnen Platzhalter handelt, und um eine Bestätigung bitten sowie angeben, in welchem ​​Verzeichnis Sie sich tatsächlich befinden.


Abgesehen davon gibt es eine Reihe von rmErsetzungen da draußen. Viele versuchen, mit dem Desktop-Papierkorb der Benutzeroberfläche kompatibel zu sein. Einige davon könnten einen Blick wert sein.

user3082
quelle
6
Ihr "Entfernen" -Alias ​​wird niemals mehr als eine Datei gleichzeitig entfernen. Sie können keine Platzhalter verwenden, da die Shell sie erweitert, bevor der Befehl sie sieht.
Hymie
Führen Sie also eine Auswertung durch und ziehen Sie diese dann in das Skript ein?
user3082
Also willst du tippen remove \*? Wenn Ihr Skript die Eingabe der Shell-Glob-Erweiterung zulässt, kann ich nicht viel damit anfangen.
Peter Cordes
0

Ein sehr einfacher Trick ist es, -rfam Ende zu setzen : rm whatever* -rf
Dadurch wird die Fehlerrate drastisch reduziert, da Sie mehr Zeichen nach dem *eingeben, damit Sie mehr Zeit haben, Tippfehler zu sehen.
Das löst nicht alles. Nur ein einfacher alltäglicher Trick.

Gregory MOUSSAT
quelle