Wie stabil sind die „stdin / stdout APIs“ der Unix-Shell?


20

Grepping, Awking, Sedding und Piping gehören zur täglichen Routine eines Benutzers eines Unix-ähnlichen Betriebssystems, sei es in der Befehlszeile oder in einem Shell-Skript ( von nun an gemeinsam Filter genannt ).

Im Wesentlichen benötigen Filter bei der Arbeit mit "Standard" -Unix-CLI-Programmen und Shell-Builtins ( von nun an gemeinsam Befehle genannt ) ein genaues erwartetes Format für stdin, stdout und stderr in jedem Filterschritt, um korrekt zu funktionieren. Ich bezeichne dieses genaue erwartete Format eines Befehls im Folgenden als API dieses Befehls.

Als jemand mit Webentwicklungshintergrund vergleiche ich diese Art der Datenerfassung und Datenverarbeitung technisch mit Web-Scraping - eine Technik, die sehr instabil ist, wenn sich die Datenpräsentation geringfügig ändert.

Meine Frage bezieht sich nun auf die Stabilität von Unix-Befehls-APIs.

  1. Halten Befehle in Unix-ähnlichen Betriebssystemen eine formale Standardisierung in Bezug auf ihre Eingabe und Ausgabe ein?
  2. Gab es in der Vergangenheit Fälle, in denen Aktualisierungen eines wichtigen Befehls dazu geführt haben, dass die Funktionalität eines Filters, der mit einer älteren Version dieses Befehls erstellt wurde, beeinträchtigt wurde?
  3. Sind Unix-Befehle im Laufe der Zeit so ausgereift, dass es absolut unmöglich ist, sie so zu ändern, dass ein Filter kaputt gehen könnte?
  4. Wie kann ich als Entwickler meine Filter vor diesem Problem schützen, falls Filter aufgrund geänderter Befehls-APIs von Zeit zu Zeit ausfallen?

Antworten:


17

Der POSIX 2008-Standard enthält einen Abschnitt, der "Shell und Dienstprogramme" beschreibt . Wenn Sie dabei bleiben, sollten Ihre Skripte im Allgemeinen ziemlich zukunftssicher sein, mit Ausnahme von möglichen Abwertungen. Diese treten jedoch kaum über Nacht auf, sodass Sie genügend Zeit haben sollten, um Ihre Skripte zu aktualisieren.

In einigen Fällen , in denen Ausgabeformat für ein einzelnes Dienstprogramm weit über Plattformen und Versionen variieren, kann der POSIX - Standard eine Option enthält in der Regel genannt -poder -Peine , die angibt , garantiert und berechenbares Ausgabeformates. Ein Beispiel hierfür ist das timeDienstprogramm , das sehr unterschiedliche Implementierungen aufweist. Wenn Sie ein stabiles API- / Ausgabeformat benötigen, verwenden Sie time -p.

Wenn Sie ein Filter-Dienstprogramm verwenden müssen, das nicht vom POSIX-Standard abgedeckt wird, sind Sie den Distributions-Packagern / Upstream-Entwicklern so gut wie den Remote-Web-Entwicklern beim Web-Scraping ausgeliefert.


12

Ich werde versuchen, aus meiner Erfahrung zu antworten.

  1. Befehle halten sich nicht wirklich an eine formale Spezifikation, aber sie halten sich an eine Anforderung, zeilenorientierten Text zu konsumieren und zu generieren.

  2. Ja natürlich. Bevor die GNU-Dienstprogramme zum De-facto-Standard wurden, hatten viele Anbieter eine eigenwillige Ausgabe, insbesondere in Bezug auf psund ls. Dies verursachte große Schmerzen. Heutzutage liefert nur HP außergewöhnliche Befehle. In der Vergangenheit waren die BSD-Dienstprogramme (Berkeley Software Distribution) ein wichtiger Bruch mit der Vergangenheit. Die POSIX-Spezifikation war ein Bruch mit der Vergangenheit, aber jetzt ist sie weithin akzeptiert.

  3. Unix-Befehle sind in der Tat mit der Zeit gereift. Es ist immer noch nicht unmöglich, ein Skript zu brechen, das für eine ältere Version geschrieben wurde. Denken Sie an den jüngsten Trend zu UTF-8 als Textdateicodierung. Diese Änderung erforderte die Änderung grundlegender Dienstprogramme wie tr. In der Vergangenheit war einfacher Text fast immer ASCII (oder etwas Nahes), sodass Großbuchstaben ebenso wie Kleinbuchstaben einen numerischen Bereich bildeten. Bei UTF-8 ist dies nicht mehr der Fall. Daher können Sie trverschiedene Befehlszeilenoptionen akzeptieren, um z. B. "Großbuchstaben" oder "alphanumerisch" anzugeben.

  4. Eine der besten Möglichkeiten, Ihre Filter zu "verschärfen", besteht darin, nicht von einem bestimmten Textlayout abzuhängen. Zum Beispiel nicht cut -c10-24, was von der Position einer Linie abhängt. Verwenden Sie cut -f2stattdessen, um das zweite, durch Tabulatoren getrennte Feld auszublenden. awkunterteilt jede Eingabezeile in $ 1, $ 2, $ 3 ..., die standardmäßig durch Leerzeichen getrennt sind. Hängen Sie von übergeordneten Konzepten wie "Feldern" ab und nicht von untergeordneten Konzepten wie der Spaltenposition. Verwenden Sie auch reguläre Ausdrücke: sedund awkbeide können Dinge mit regulären Ausdrücken tun, bei denen es nicht auf Abweichungen bei der Eingabe ankommt. Ein weiterer Trick besteht darin, die Eingabe in ein Format umzuwandeln, bei dem Ihr Filter wählerisch sein kann. Verwenden Sie tr -cs '[a-zA-z0-9]' '[\n]'diese Option , um Text ohne Interpunktion in ein einzelnes Wort pro Zeile zu unterteilen. Du gehst einfach nicht


9

Zunächst ganz kurze Antworten auf Ihre Fragen:

  1. Formale Standardisierung von Input / Output-Konventionen: Nein
  2. Bruch in der Vergangenheit durch Leistungsänderung: ja
  3. Es ist absolut unmöglich, zukünftige Filter zu brechen: Nein
  4. Wie kann ich mich vor Veränderungen schützen: konservativ sein

Wenn Sie "API" sagen, verwenden Sie einen Begriff, der (für gut oder schlecht) zu viel Formalität in Bezug auf Filter-Eingabe- / Ausgabe-Konventionen impliziert. Sehr (und ich meine "sehr") allgemein sind die primären Konventionen für Daten, die leicht zu filtern sind

  • Jede Eingabezeile ist eine vollständige Aufzeichnung
  • In jedem Datensatz werden Felder durch ein bekanntes Trennzeichen getrennt

Ein klassisches Beispiel wäre das Format / etc / passwd. Diese Standardkonventionen werden jedoch wahrscheinlich etwas häufiger verletzt, als sie dem Buchstaben entsprechen.

  • Es gibt viele Filter (oft in awk oder perl geschrieben), die mehrzeilige Eingabeformate analysieren.
  • Es gibt viele Eingabemuster (z. B. / var / log / messages), bei denen keine genau definierte Feldstruktur vorliegt und allgemeinere auf regulären Ausdrücken basierende Techniken verwendet werden müssen.

Ihre vierte Frage, wie Sie sich vor Schwankungen in der Ausgabestruktur schützen können, ist wirklich die einzige, gegen die Sie etwas unternehmen können.

  • Schauen Sie sich, wie @ jw013 sagte , die Aussagen der posix-Standards an. Natürlich gibt posix nicht alle Befehle an, die Sie als Eingabequellen verwenden möchten.
  • Wenn Sie möchten, dass Ihre Skripte portierbar sind, vermeiden Sie die Eigenheiten der Version des Befehls, den Sie gerade installiert haben. Beispielsweise haben viele GNU-Versionen von Standard-Unix-Befehlen nicht standardmäßige Erweiterungen. Diese mögen nützlich sein, aber Sie sollten sie vermeiden, wenn Sie maximale Portabilität wünschen.
  • Versuchen Sie herauszufinden, welche Teilmengen von Befehlsargumenten und Ausgabeformaten plattformübergreifend stabil sind. Leider erfordert dies den zeitlichen Zugriff auf mehrere Plattformen, da diese Unterschiede nicht einmal informell aufgeschrieben werden.

Letztendlich können Sie sich nicht vollständig vor den Problemen schützen, über die Sie sich Sorgen machen, und es gibt keinen Ort, an dem Sie nach einer "endgültigen" Aussage darüber suchen können, was ein bestimmter Befehl tun sollte. Für viele Shellskripte, insbesondere solche, die für den persönlichen oder kleinen Gebrauch geschrieben wurden, ist dies einfach kein Problem


5

Deckt nur 1) Ihrer Frage ab.

Natürlich können APIs jederzeit nach Belieben ihrer Entwickler geändert werden und damit abhängige Software in jeder Sprache brechen. Die großartige Idee der I / O- "APIs" der Unix-Tools ist jedoch, dass es praktisch keine gibt (möglicherweise 0x0aals Zeilenende). Ein gutes Skript filtert Daten mit den Unix-Tools, anstatt sie zu erstellen. Das bedeutet, dass Ihr Skript möglicherweise nicht mehr funktioniert, weil sich die Eingabe- oder Ausgabespezifikation geändert hat, aber nicht, weil sich das E / A-Format (auch hier gibt es nicht wirklich eines) der einzelnen im Skript verwendeten Tools geändert hat (weil etwas nicht wirklich vorhanden ist) kann mich nicht wirklich ändern).

Wenn ich eine Liste grundlegender Tools durchblättere, gibt es einige, die ich auch als Produzent einstufen würde , anstatt nur zu filtern:

  • wc - Anzahl der Bytes, Wörter, Zeilen drucken - sehr einfaches Format, daher absolut unwahrscheinlich, dass es sich ändert, und außerdem nicht sehr wahrscheinlich, dass es in einem Skript verwendet wird.
  • diff - es gibt verschiedene Ausgabeformate, aber ich habe keine Probleme gehört. Auch normalerweise nicht ohne Aufsicht verwendet.
  • date - Jetzt müssen wir uns wirklich darum kümmern, was wir produzieren, insbesondere was das Gebietsschema des Systems betrifft. Ansonsten ist das Ausgabeformat RFC-fähig, da Sie es nicht genau angeben.
  • cal - reden wir nicht darüber, ich weiß, dass das Ausgabeformat von System zu System sehr unterschiedlich ist.
  • ls , who , w , last - ich kann nicht anders, wenn Sie ls analysieren wollen, es sollte einfach nicht sein. Auch wer, w, zuletzt, sind mehr interaktive Listener; Wenn Sie sie in einem Skript verwenden, müssen Sie darauf achten, was Sie tun.
  • auf die zeit wurde in einem anderen post hingewiesen. Aber ja, es ist dasselbe wie bei ls. Mehr für den interaktiven / lokalen Gebrauch. Und die Bash-Version unterscheidet sich stark von der GNU-Version, und die GNU-Version hat seit vielen Jahren Fehler beseitigt. Verlasse dich einfach nicht darauf.

Die folgenden Tools erwarten ein bestimmtes Eingabeformat, das spezifischer ist als ein Byte-Stream:

  • bc , dc - rechner. Bereits auf der hackigeren Seite der Dinge (wirklich, ich benutze sie nicht in Skripten) und vermutlich sehr stabile I / O-Formate.

Es gibt einen anderen Bereich mit einem viel höheren Bruchrisiko, nämlich die Befehlszeilenschnittstelle. Die meisten Tools haben unterschiedliche Funktionen sowohl auf den Systemen als auch auf der Zeitachse. Beispiele sind

  • Alle Tools, die Regex verwenden - Regex kann die Bedeutung basierend auf dem Gebietsschema des Systems ändern (z. B. LC_COLLATE) und es gibt viele Feinheiten und Besonderheiten bei allen Implementierungen von Regex.
  • Verwenden Sie einfach keine ausgefallenen Schalter. Sie können beispielsweise einfach man 1p finddie POSIX-Such-Manpage anstelle der System-Manpage lesen. Auf meinem System muss manpages-posix installiert sein.

Und selbst wenn Sie solche Schalter verwenden, werden normalerweise keine subtilen Fehler verursacht, die Ihre Daten vergiften. Die meisten Programme lehnen es einfach ab, mit einem unbekannten Schalter zu arbeiten.

Abschließend würde ich sagen, dass Shell tatsächlich das Potenzial hat, eine der portabelsten Sprachen zu sein (es ist portabel, wenn Sie portabel schreiben). Vergleichen Sie mit Ihren bevorzugten Skriptsprachen, in denen subtile Fehler auftreten, oder mit Ihrem bevorzugten kompilierten Programm, das nicht mehr kompiliert werden kann.

An den seltenen Stellen, an denen ein Bruch aufgrund von Inkompatibilitäten auftreten kann, ist dies wahrscheinlich nicht auf die Zeit zurückzuführen, sondern auf die Verschiedenartigkeit der verschiedenen Systeme (was bedeutet, dass dies bei Ihnen 20 Jahre zuvor und in 20 Jahren der Fall war) , auch). Dies ist eine Folge der Einfachheit der Werkzeuge.


1

Es gibt nur de facto IO-Standards - Whitespace- und nullgetrennte Ausgabe.

Aus Kompatibilitätsgründen überprüfen wir normalerweise die Versionsnummern der einzelnen Filter. Nicht, dass sie sich stark ändern, aber wenn Sie eine brandneue Funktion verwenden und das Skript dennoch auf älteren Versionen ausführen möchten, müssen Sie es irgendwie "ifdef". Es gibt praktisch keinen Mechanismus zum Melden von Fähigkeiten, außer zum manuellen Schreiben von Testfällen.


0

Einige Skripte brechen häufiger ab als andere. Die alte und berühmte Software bleibt in der Regel relativ gleich und weist häufig Kompatibilitätsflags auf, wenn sie sich dennoch ändert.

Skripte, die auf einem System geschrieben wurden, funktionieren normalerweise weiterhin, brechen jedoch häufig andere.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.