Ich habe cp
mit folgenden Befehlen getestet :
$ ls
first.html second.html third.html
$ cat first.html
first
$ cat second.html
second
$ cat third.html
third
Dann kopiere ich first.html
nach second.html
:
$ cp first.html second.html
$ cat second.html
first
Die Datei second.html
wird unbemerkt ohne Fehler überschrieben. Wenn ich es jedoch in einer Desktop-Benutzeroberfläche durch Ziehen und Ablegen einer Datei mit demselben Namen mache, wird sie first1.html
automatisch mit einem Suffix versehen . Dadurch wird verhindert, dass eine vorhandene Datei versehentlich überschrieben wird.
Warum folgt cp
man diesem Muster nicht, anstatt Dateien still zu überschreiben?
cp
zucp -i
oder ähnlich , weil Sie ein Sicherheitsnetz mit gewöhnungs werden, so dass Systeme , bei denen es nicht möglich ist ( die meisten von ihnen), die viel riskanter. Es ist besser, sich routinemäßigcp -i
usw. beizubringen, wenn Sie dies bevorzugen.Antworten:
Das Standard-Überschreibverhalten von
cp
ist in POSIX festgelegt.Als die POSIX-Spezifikation geschrieben wurde, gab es bereits eine große Anzahl von Skripten mit einer integrierten Annahme für das Standardüberschreibverhalten. Viele dieser Skripte wurden entwickelt, um ohne direkte Benutzerpräsenz ausgeführt zu werden, z. B. als Cron-Jobs oder andere Hintergrundaufgaben. Eine Änderung des Verhaltens hätte sie kaputt gemacht. Sie alle zu überprüfen und zu ändern, um eine Option hinzuzufügen, mit der das Überschreiben erzwungen werden kann, wo immer dies erforderlich war, wurde wahrscheinlich als große Aufgabe mit minimalen Vorteilen angesehen.
Außerdem wurde die Unix-Befehlszeile immer so gestaltet, dass erfahrene Benutzer effizient arbeiten können, auch auf Kosten einer schwierigen Lernkurve für Anfänger. Wenn der Benutzer einen Befehl eingibt, muss der Computer davon ausgehen, dass der Benutzer ihn wirklich meint, ohne dass er etwas anderes erraten muss. Es liegt in der Verantwortung des Benutzers, mit potenziell zerstörerischen Befehlen vorsichtig umzugehen.
Als das ursprüngliche Unix entwickelt wurde, hatten die Systeme im Vergleich zu modernen Computern so wenig Speicher und Massenspeicher, dass das Überschreiben von Warnungen und Eingabeaufforderungen wahrscheinlich als verschwenderischer und unnötiger Luxus angesehen wurde.
Als der POSIX-Standard geschrieben wurde, war der Präzedenzfall fest verankert, und die Verfasser des Standards waren sich der Tugenden bewusst, die Abwärtskompatibilität nicht zu brechen .
Außerdem kann, wie andere beschrieben haben, jeder Benutzer diese Funktionen für sich selbst hinzufügen / aktivieren, indem er Shell-Aliase verwendet oder sogar einen Ersetzungsbefehl erstellt
cp
und diesen modifiziert$PATH
, um die Ersetzung vor dem Standardsystembefehl zu finden, und das Sicherheitsnetz auf diese Weise abrufen, wenn erwünscht.Aber wenn Sie dies tun, werden Sie feststellen, dass Sie eine Gefahr für sich selbst schaffen. Wenn sich der
cp
Befehl bei interaktiver Verwendung auf eine andere Art und Weise verhält, als wenn er von einem Skript aus aufgerufen wird, können Sie sich möglicherweise nicht daran erinnern, dass der Unterschied besteht. Auf einem anderen System könnten Sie leichtsinnig werden, weil Sie sich an die Warnungen und Eingabeaufforderungen auf Ihrem eigenen System gewöhnt haben.Wenn das Verhalten in Skripten weiterhin dem POSIX-Standard entspricht, werden Sie sich wahrscheinlich an die Eingabeaufforderungen im interaktiven Gebrauch gewöhnen. Schreiben Sie dann ein Skript, das Massenkopien ausführt, und stellen Sie dann fest, dass Sie versehentlich etwas überschrieben haben.
Was kann der Befehl tun, wenn Sie die Eingabeaufforderung auch in Skripten erzwingen, wenn er in einem Kontext ausgeführt wird, in dem sich kein Benutzer befindet, z. B. Hintergrundprozesse oder Cron-Jobs? Wird das Skript hängen bleiben, abgebrochen oder überschrieben?
Hängen oder Abbrechen bedeutet, dass eine Aufgabe, die automatisch erledigt werden sollte, nicht erledigt wird. Das Nicht-Überschreiben kann manchmal auch selbst zu Problemen führen: Beispielsweise werden alte Daten möglicherweise zweimal von einem anderen System verarbeitet, anstatt durch aktuelle Daten ersetzt zu werden.
Ein großer Teil der Leistungsfähigkeit der Befehlszeile beruht auf der Tatsache, dass Sie , sobald Sie wissen, wie etwas in der Befehlszeile zu tun ist, implizit auch wissen, wie dies durch Skripterstellung automatisch geschehen kann . Dies gilt jedoch nur, wenn die Befehle, die Sie interaktiv verwenden, auch in einem Skript-Kontext genauso funktionieren. Jegliche signifikanten Unterschiede im Verhalten zwischen der interaktiven Verwendung und der Verwendung von Skripten führen zu einer Art kognitiver Dissonanz, die für einen Power-User ärgerlich ist.
quelle
rm -rf
so effektiv ist, auch wenn Sie ihn nicht in Ihrem Home-Verzeichnis ausführen wollten ...cp
kommt von Anfang an von Unix. Es war dort, lange bevor der Posix-Standard geschrieben wurde. In der Tat: Posix hat gerade das bestehende Verhaltencp
in dieser Hinsicht formalisiert .Wir reden über Epoche (1970-01-01), als Männer echte Männer waren, Frauen echte Frauen und pelzige kleine Kreaturen ... (ich schweife ab). In jenen Tagen vergrößerte das Hinzufügen von zusätzlichem Code ein Programm. Das war damals ein Problem, denn der erste Computer, auf dem Unix lief, war ein PDP-7 (aufrüstbar auf 144 KB RAM!). Die Dinge waren also klein, effizient und ohne Sicherheitsmerkmale.
In jenen Tagen musste man also wissen, was man tat, weil der Computer einfach nicht in der Lage war, Sie daran zu hindern, etwas zu tun, was Sie später bereuten.
(Es gibt einen schönen Cartoon von Zevar; suchen Sie nach "zevar cerveaux assiste par ordinateur", um die Entwicklung des Computers zu ermitteln. Oder versuchen Sie es unter http://perinet.blogspirit.com/archive/2012/02/12/zevar-et- cointe.html solange es existiert)
Für diejenigen, die wirklich interessiert sind (ich habe einige Spekulationen in den Kommentaren gesehen): Das Original
cp
auf dem ersten Unix enthielt ungefähr zwei Seiten Assembler-Code (C kam später). Der relevante Teil war:(Also ein harter
sys creat
)Und wenn wir schon dabei sind: Version 2 von Unix verwendet (Code-Sniplet)
das ist auch ein hartes
creat
ohne tests oder absicherungen. Beachten Sie, dass der C-Code für V2 Unixcp
weniger als 55 Zeilen enthält!quelle
cp
nuropen
ed das Ziel mitO_CREAT | O_TRUNC
und führte eineread
/write
Schleife; Sicher, mit moderncp
gibt es so viele Knöpfe, dass es im Grunde genommenstat
vorher versuchen muss, das Ziel zu erreichen, und es könnte leicht zuerst auf Existenz überprüft werden (und tut dies mitcp -i
/cp -n
), aber wenn die Erwartungen von originalen, nacktencp
Werkzeugen erfüllt würden , würde sich dieses Verhalten ändern würde bestehende Skripte unnötig brechen. Es ist nicht so, alsalias
könnten moderne Shells nicht einfachcp -i
den Standard für die interaktive Verwendung festlegen.creat
zufällig mitopen
+ gleichzusetzenO_CREAT | O_TRUNC
), aber das Fehlen vonO_EXCL
does erklärt, warum es nicht so einfach gewesen wäre, mit vorhandenen Dateien umzugehen; so wäre von Natur aus rassig zu tun versuchen (Sie würden im Grunde müssenopen
/stat
Existenz zu überprüfen, dann verwendencreat
, aber auf große verteilten Systemen, ist es immer möglich , durch die Zeit , die du bekommencreat
, jemand anderes die Datei gemacht und jetzt haben Sie geblasen es sowieso weg). Kann auch nur bedingungslos überschreiben.Weil diese Befehle auch in Skripten verwendet werden sollen, die möglicherweise ohne menschliche Aufsicht ablaufen, und weil es in vielen Fällen tatsächlich Fälle gibt, in denen Sie das Ziel überschreiben möchten (die Philosophie der Linux-Shells ist, dass der Mensch weiß, was Sie macht)
Es gibt noch ein paar Sicherheitsvorkehrungen:
cp
hat eine-n
|--no-clobber
Möglichkeitcp
wird beanstandet, dass die letzte kein Verzeichnis ist.quelle
Dieser Kommentar klingt wie eine Frage nach einem allgemeinen Konstruktionsprinzip. Oft sind Fragen dazu sehr subjektiv, und wir können keine richtige Antwort schreiben. Seien Sie gewarnt, dass wir in diesem Fall Fragen schließen können.
Manchmal haben wir eine Erklärung für die ursprüngliche Designauswahl, weil die Entwickler darüber geschrieben haben. Aber ich habe keine so schöne Antwort auf diese Frage.
Warum
cp
ist das so?Das Problem ist, dass Unix über 40 Jahre alt ist.
Wenn Sie jetzt ein neues System erstellen, treffen Sie möglicherweise andere Entwurfsentscheidungen. Aber das Ändern von Unix würde bestehende Skripte beschädigen, wie in anderen Antworten erwähnt.
Warum wurde
cp
entwickelt, um vorhandene Dateien stillschweigend zu überschreiben?Die kurze Antwort lautet "Ich weiß nicht" :-).
Verstehe, dass dies
cp
nur ein Problem ist. Ich denke, dass keines der ursprünglichen Befehlsprogramme gegen das Überschreiben oder Löschen von Dateien geschützt ist. Die Shell hat ein ähnliches Problem beim Umleiten der Ausgabe:Dieser Befehl überschreibt auch unbemerkt
second.html
.Ich bin gespannt, wie all diese Programme umgestaltet werden könnten. Dies erfordert möglicherweise zusätzliche Komplexität.
Ich denke, das ist ein Teil der Erklärung: Frühes Unix betonte einfache Implementierungen . Eine ausführlichere Erklärung finden Sie unter "Schlechter ist besser" am Ende dieser Antwort.
Sie können es ändern,
> second.html
sodass es mit einem Fehler beendet wird, falls essecond.html
bereits vorhanden ist. Aber wie bereits erwähnt, manchmal der Benutzer nicht will , eine vorhandene Datei ersetzen. Zum Beispiel kann sie ein komplexes Kommando aufbauen und es mehrmals versuchen, bis es das tut, was sie will.Der Benutzer kann
rm second.html
zuerst ausgeführt werden, wenn dies erforderlich ist. Dies könnte ein guter Kompromiss sein! Es hat einige mögliche eigene Nachteile.rm
. Deshalb möchte ich auchrm
sicherer machen . Aber wie? Wenn wirrm
jeden Dateinamen anzeigen lassen und den Benutzer zur Bestätigung auffordern, muss er nun drei Befehlszeilen anstatt einer schreiben . Wenn sie dies zu oft tun muss, wird sie es sich zur Gewohnheit machen und "y" eingeben, um es zu bestätigen, ohne nachzudenken. Es könnte also sehr nervig und trotzdem gefährlich sein.Auf einem modernen System empfehle ich , den
trash
Befehl zu installieren und stattdessen zu verwenden,rm
wo dies möglich ist. Die Einführung von Trash Storage war eine großartige Idee, z. B. für einen grafischen Einzelbenutzer-PC .Ich denke, es ist auch wichtig, die Einschränkungen der ursprünglichen Unix-Hardware zu kennen - begrenzter RAM- und Festplattenspeicher, Ausgabe auf langsamen Druckern sowie System- und Entwicklungssoftware.
Beachten Sie, dass das ursprüngliche Unix keine Tab-Vervollständigung hatte , um schnell einen Dateinamen für einen
rm
Befehl einzugeben . (Außerdem verfügt die ursprüngliche Bourne-Shell nicht über einen Befehlsverlauf, z. B. wenn Sie die Aufwärtspfeiltaste verwendenbash
).Bei der Druckerausgabe würden Sie den zeilenbasierten Editor verwenden
ed
. Dies ist schwerer zu lernen als ein visueller Texteditor. Sie müssen einige aktuelle Zeilen drucken, entscheiden, wie Sie sie ändern möchten, und einen Bearbeitungsbefehl eingeben.Using
> second.html
ähnelt der Verwendung eines Befehls in einem Zeileneditor. Die Auswirkung hängt vom aktuellen Status ab. (Wennsecond.html
bereits vorhanden, wird der Inhalt verworfen.) Wenn der Benutzer sich über den aktuellen Status nicht sicher ist, wird erwartet, dass er ausgeführt wirdls
oderls second.html
zuerst."Einfache Implementierung" als Gestaltungsprinzip
Es gibt eine populäre Interpretation von Unix-Design, die beginnt:
quelle
cp
einem "Problem" überschrieben ? Wenn es interaktiv um Erlaubnis bittet oder fehlschlägt, kann dies ein ebenso großes "Problem" sein.cat first.html second.html > first.html
es,first.html
wennsecond.html
nur der Inhalt von überschrieben wird . Der ursprüngliche Inhalt geht für immer verloren.Das Design von "cp" geht auf das ursprüngliche Design von Unix zurück. Es gab tatsächlich eine kohärente Philosophie hinter dem Unix-Design, die etwas weniger war, als halb im Scherz Worse-is-Better * genannt wurde .
Die Grundidee ist, dass die Vereinfachung des Codes eine wichtigere Überlegung im Hinblick auf das Design ist, als eine perfekte Benutzeroberfläche zu haben oder "das Richtige zu tun".
( Hervorhebung von mir )
Denken Sie daran, dass dies 1970 war, der Anwendungsfall von "Ich möchte diese Datei kopieren Wenn man nur wenn sie noch nicht existiert" für jemanden, der eine Kopie durchführt, ein ziemlich seltener Anwendungsfall gewesen. Wenn Sie das möchten, können Sie dies durchaus vor der Kopie überprüfen, und das kann sogar per Skript erfolgen.
Der Autor des Aufsatzes hatte auch eine Theorie dazu, warum ein Betriebssystem mit diesem Entwurfsansatz dasjenige war, das sich gegen alle anderen damals gebauten Betriebssysteme durchgesetzt hat.
* - oder was der Autor, aber sonst niemand, "The New Jersey Approach" nannte .
quelle
creat()
vsopen()
.open()
Konnte eine Datei erstellen , wenn es nicht existieren. Es dauert nur 0/1/2 für Lesen / Schreiben / beides. Es ist noch nicht nehmenO_CREAT
, und es gibt keineO_EXCL
).Der Hauptgrund ist, dass eine GUI per definitionem interaktiv ist, während eine binäre Oberfläche
/bin/cp
nur ein Programm ist, das von allen möglichen Stellen aus aufgerufen werden kann, zum Beispiel von Ihrer GUI aus ;-). Ich wette, dass auch heute die meisten Anrufe/bin/cp
nicht von einem realen Terminal kommen, bei dem ein Benutzer einen Shell-Befehl eingibt, sondern von einem HTTP-Server, einem Mail-System oder einem NAS. Ein integrierter Schutz vor Benutzerfehlern ist in einer interaktiven Umgebung absolut sinnvoll. weniger in einer einfachen binären. Zum Beispiel wird Ihre GUI höchstwahrscheinlich/bin/cp
den Hintergrund aufrufen , um die eigentlichen Vorgänge auszuführen, und müsste sich mit den Sicherheitsfragen zu Standard Out befassen, obwohl sie nur den Benutzer gefragt hat!Beachten Sie, dass es vom ersten Tag an beinahe trivial war, auf
/bin/cp
Wunsch einen sicheren Wrapper zu schreiben . Die * nix-Philosophie besteht darin, den Benutzern einfache Bausteine zur Verfügung zu stellen/bin/cp
.quelle