Warum kann ed nicht mit Cc beendet werden?

20

Das Programm ed, ein Minimal-Texteditor, kann nicht durch Senden eines Interrupts mit Ctrl- beendet Cwerden. Stattdessen wird die Fehlermeldung "?" zur Konsole. Warum wird nicht edeinfach beendet, wenn der Interrupt eingeht? Sicher gibt es keinen Grund, warum eine kryptische Fehlermeldung hier nützlicher ist als nur zu beenden. Dieses Verhalten führt viele neue Benutzer zu der folgenden Art von Interaktion:

$ ed
hello
?
help
?
exit
?
quit
?
^C
?
^C
?
?
?
^D
$ su
# rm -f /bin/ed

Solch eine tragische Verschwendung - leicht vermeidbar, wenn edeinfach zugestimmt wird, unterbrochen zu werden.

Ein anderes hartnäckiges Programm, das ein ähnliches Verhalten aufweist less, scheint auch nicht viel Grund zu haben, es zu ignorieren C-c. Warum nehmen diese Programme nicht einfach einen Hinweis?

Lily Chung
quelle
4
Interaktive Anwendungen sind nicht dasselbe wie nicht interaktive. Das gewohnte Ctrl-C-Verhalten ist die Standardeinstellung für nicht interaktive. Die interaktiven können das Verhalten von Strg-C für ihre eigenen Zwecke überschreiben.
JW013
4
Auch nicht sicher, ob Witz
jw013
@ jw013 Ja, die "typische Sitzung" war ein Witz (ich konnte sie aus irgendeinem Grund nicht finden), aber meine Frage ist ernst. Was ich nicht verstehe, ist, warum diese Anwendungen das Verhalten von Strg-C außer Kraft setzen, wenn es eigentlich nichts Nützliches bietet.
Lily Chung
1
Da diese Frage bei der Google-Suche als Antwort auf die Frage nach dem Beenden von ed am häufigsten gestellt wird, möchte ich hier hinzufügen, dass es sich nur um ein "q" handelt, gefolgt von einem "return". Viele Bothans starben, um uns diese Informationen zu bringen.
Dmitri

Antworten:

19

Ctrl+ CSendet SIGINT . Die herkömmliche Aktion für SIGINT besteht darin, zur obersten Schleife eines Programms zurückzukehren, den aktuellen Befehl abzubrechen und in einen Modus zu wechseln, in dem das Programm auf den nächsten Befehl wartet. Nur nicht interaktive Programme sollen an SIGINT sterben.

Es ist also natürlich, dass Ctrl+ Ced nicht tötet, sondern zu seiner obersten Schleife zurückkehrt. Ctrl+ Cbricht die aktuelle Eingabezeile ab und kehrt zur Eingabeaufforderung ed zurück.

Gleiches gilt für weniger: Ctrl+ Cunterbricht den aktuellen Befehl und bringt Sie zurück zur Eingabeaufforderung.

Aus historischen Gründen ignoriert ed SIGQUIT ( Ctrl+ \). Normale Anwendungen sollten dieses Signal nicht abfangen und sich beenden lassen, wenn ein Core-Dump aktiviert ist.

Gilles 'SO - hör auf böse zu sein'
quelle
@ Kzqai Nein, normale Anwendungen sollten SIGQUIT nicht fangen, es ist als Notausgang gedacht.
Gilles 'SO- hör auf böse zu sein'
Ah, gotcha. Okay, zurückgezogen.
Kzqai
18

Der Unix V7- ed(1)Quellcode ist ein primitives C-Programm mit 1.762 Zeilen und nur wenigen Kommentaren.

/*
 * Editor
 */

Da der Quellcode selbst keine Begründung liefert, erhalten Sie ihn nur vom Autor des Programms.

edwurde ursprünglich von Ken Thompson in der PDP-11-Assembly geschrieben , aber Sie müssten tatsächlich mit demjenigen sprechen, der es auf C portiert hat. Das könnte Dennis Ritchie gewesen sein , da er C für Unix erstellt hat und einer von vielen, die C früher verwendet haben Unix für Nicht-PDP-Computer portierbar machen. Dr. Ritchie ist jedoch nicht mehr da, um solche Fragen zu beantworten.

Das Lesen des Codes legt nahe, dass versucht wurde, den Inhalt der In-Core- Kopie des bearbeiteten Dokuments beizubehalten. Sie werden bemerken, dass auch andere Texteditoren nicht daran sterben Ctrl-C.

Hier ist was edpassiert Ctrl-C:

onintr()
{
    signal(SIGINT, onintr);
    putchr('\n');
    lastc = '\n';
    error(Q);
}

(Ja, K & R C. Wir brauchen keine steenkin 'Rückgabetypspezifizierer oder Parameterdeklarationen.)

Übersetzt ins Englische ed:

  1. Registriert den Signalhandler neu.

    (Unix hat erst Mitte der 1980er Jahre mit 4.3BSD Signale zum automatischen Zurücksetzen erhalten .)

  2. Schreibt eine neue Zeile aus und merkt sich dies über die globale Variable lastc.

    ( ed.cHat ungefähr sechzig globale Variablen.)

  3. Ruft die error()Funktion aus der Sicht des Benutzers auf , die bekanntlich kaum mehr als Drucken leistet ?.

Mit anderen Worten heißt es: "Das wolltest du doch eigentlich nicht, oder?"

Warren Young
quelle
2
Erwähnenswert ist auch, dass viele Texteditoren bei Control-C nicht beendet werden. Vim auch nicht. Nano auch nicht. Ich glaube auch nicht, dass Emacs das tut, aber ich habe es nicht installiert, um es zu testen.
Derobert
3
@derobert Vi behandelt Strg + C auf Unix-Weise: Gehe zurück zur obersten Ebene. Emacs hat aufgrund seiner Nicht-Unix-Ursprünge seine eigenen Tastenkombinationen. Das Emacs-Äquivalent zu Unix 'Strg + C ist Strg + G (der Klingelcharakter - klingeln Sie am Computer, um ihn zu unterbrechen)
Gilles' SO - hör auf, böse
@derobert: Guter Punkt. Ich habe dies zur Antwort hinzugefügt.
Warren Young
2
@Gilles: Eine der Nebenwirkungen von Aufrufen error(s)in ed.cist mit der Hauptverarbeitungsschleife zurück. Dies geschieht mit einem longjmp()Anruf. Schauder
Warren Young
1
Vielen Dank für die Details und die Geschichtsstunde. Das war eine großartige Lektüre!
Alichaudry
7

edVerwenden Sie, wie bei anderen interaktiven Programmen, Ctrl+, Cum Aufgaben des Programms selbst zu unterbrechen.
Dies ist dem normalen Fall sehr ähnlich, in dem eine in der Shell ausgeführte Task unterbrochen wird - ein Befehl.

Beide Varianten sind sich aus Anwendersicht sehr ähnlich. Die Behandlung des Signals ist unterschiedlich: Im Normalfall wird das Signal SIGINTan den Vordergrundprozess gesendet, ein ausgeführter Befehl, und der Befehl verarbeitet es durch Beenden.
Im Falle von edwird das Signal an den Vordergrundprozeß der edInstanz gesendet . Wenn eine Aufgabe ausgeführt wird ed, wird sie unterbrochen und die Eingabeaufforderung angezeigt. Wenn keine Aufgabe ausgeführt wird, wird nichts geändert.

Beachten Sie, wie eine Shell auch nicht auf Ctrl+ beendet Cwird ed. Und dass es auf Ctrl+ beendet D. Wieder wieed

Volker Siegel
quelle
3

Es gibt drei Signale, die edwichtig sind:

  1. INT
  2. HUP
  3. QUIT

In der POSIX-Spezifikation voned heißt es dazu:

SIGINT

Das edDienstprogramm unterbricht seine aktuelle Aktivität, schreibt den String ?\nin die Standardausgabe und kehrt in den Befehlsmodus zurück (siehe Abschnitt ERWEITERTE BESCHREIBUNG).

SIGHUP

Wenn der Puffer nicht leer ist und sich seit dem letzten Schreiben geändert hat, versucht das edDienstprogramm, eine Kopie des Puffers in eine Datei zu schreiben. Zunächst wird die ed.hupim aktuellen Verzeichnis angegebene Datei verwendet. Wenn dies fehlschlägt, wird die Datei verwendet, die ed.hupin dem von der HOMEUmgebungsvariablen angegebenen Verzeichnis angegeben ist. In jedem Fall wird das edDienstprogramm beendet, ohne die Datei in den aktuell gespeicherten Pfadnamen zu schreiben und ohne in den Befehlsmodus zurückzukehren.

SIGQUIT

Das edDienstprogramm ignoriert dieses Ereignis.

Unabhängig davon, welche Implementierung edSie verwenden, entspricht sie der POSIX-Spezifikation in Bezug auf das INTSignal (welches Ctrl+Csendet).

In dieser Hinsicht verhält sich der Editor wie eine interaktive Shell, die auch beim Empfang des INTSignals nicht beendet wird . Andere Editoren wie viund machen nanodas Gleiche.

Kusalananda
quelle
1
Einige Programmimplementierungen stehen bewusst im Widerspruch zu POSIX. In diesem Fall kann es daher hilfreich sein, die Gründe für den Standard bzw. die Kosten für die Fehlerbehebung zu erläutern. stackoverflow.com/questions/38605463/…
sourcejedi
1
@sourcejedi Der Standard sagt in seiner Begründung nichts über die Signale aus. Ich habe keine Begründung dafür gefunden, warum der Standard in den edmir vorliegenden Quellen befolgt wird . Es verhält sich ähnlich wie die Shell, die auch beim Empfang des INTSignals nicht terminiert .
Kusalananda