Gibt es einen Unterschied zwischen read, head -1 und sed 1q?

7

Die folgenden Befehle scheinen ungefähr gleichwertig zu sein:

read varname
varname=$(head -1)
varname=$(sed 1q)

Ein Unterschied ist, dass readeine Shell eingebaut ist headund sednicht.

Gibt es außerdem einen Unterschied im Verhalten zwischen den drei?

Meine Motivation ist es, die Nuancen der Shell und der wichtigsten Dienstprogramme wie besser zu verstehen head,sed. Wenn die Verwendung headbeispielsweise ein einfacher Ersatz für ist read, warum gibt reades sie dann als integrierte Funktion?

Tyler
quelle

Antworten:

6

Weder Effizienz noch Aufbau sind der größte Unterschied. Alle geben für bestimmte Eingaben unterschiedliche Ausgaben zurück.

  • head -n1 wird nur dann eine nachfolgende neue Zeile bereitstellen, wenn die Eingabe eine hat.

  • sed 1q liefert immer einen nachgestellten Zeilenumbruch, behält aber ansonsten die Eingabe bei.

  • read wird niemals einen nachgestellten Zeilenumbruch bereitstellen und Backslash-Sequenzen interpretieren.

Darüber hinaus stehen readzusätzliche Optionen zur Verfügung, z. B. Aufteilen, Zeitüberschreitungen und Eingabeverlauf, von denen einige Standard sind und andere zwischen den Shells variieren.

o11c
quelle
Vielen Dank. Diese Verhaltensunterschiede sind das, wonach ich gesucht habe. Ich mag es auch zu wissen, dass, wie @ glenn-jackman betonte, readParameter analysiert werden können, die durch das interne Feldtrennzeichen getrennt sind $IFS. @ rameshs straceTrick ist auch eine großartige Möglichkeit, Unterschiede zu analysieren.
Tyler
5

Zum einen können Sie Text mit Lesen analysieren und nicht nur eine ganze Zeile

echo "foo:bar:baz" | {
  IFS=: read one two three
  echo $two
}
Glenn Jackman
quelle
Sie analysieren es nicht readgenau, Sie analysieren es mit $IFS. IFS=:; set -- ${0+foo:bar:baz}; echo "$2"erreicht das gleiche - und es erfordert keine |pipesoder geklonte Unterschalen. Oder : IFS=:; printf %.0s%s%.0s\\n ${0+foo:bar:baz}. Sonst: echo foo:bar:baz | { IFS=:; set -- $(cat); echo "$2"; }wenn du das Rohr haben musst. In jedem Fall ist die Aufteilung ein Ergebnis Ihrer Einstellung $IFS; nicht unbedingt, dass du reades.
Mikesserv
2
Wahr. readweist die geteilten Teile Variablen zu.
Glenn Jackman
5

Builtins sind vorhanden, um die Systemaufrufe schneller zu machen. Daher glaube ich, dass der readBefehl als integrierter Bestandteil vorhanden ist, um effizienter zu sein.

Zitat von hier ,

Diese integrierten Befehle sind Teil der Shell und werden als Teil des Quellcodes der Shell implementiert. Die Shell erkennt, dass der Befehl, den sie ausführen soll, einer ihrer integrierten Befehle ist, und führt diese Aktion selbst aus, ohne eine separate ausführbare Datei aufzurufen. Unterschiedliche Shells haben unterschiedliche Einbauten, obwohl es im Basissatz eine Menge Überlappungen gibt.

Nun möchte ich, dass dies selbst experimentiert wird, damit Sie verstehen, warum reades als eingebaute Shell vorhanden ist.

Normalerweise kann man keine straceShell-Builds verwenden. Es gibt jedoch auch hierfür eine Problemumgehung. Dies wird in dieser Antwort ziemlich genau erklärt .

  1. Führen Sie in der ersten Shell den Befehl als aus stty -echo.
  2. Öffnen Sie eine andere Shell und führen Sie den Befehl als aus cat | strace bash > /dev/null.
  3. Jetzt würde die Shell darauf warten, dass der Benutzer die Befehle eingibt. Wenn der Benutzer die Befehle eingibt, können Sie sehen, was auch auf Systemebene passiert.
  4. Wenn Sie die obigen 3 Befehle eingeben, können Sie feststellen, dass read weniger Systemaufrufe hat als die verbleibenden 2 Befehle. Ich füge die Ausgabe nicht ein, straceda sie ziemlich groß ist.
Ramesh
quelle
1
Auch das readeingebaute ist /bin/shbereits vorhanden headund wahrscheinlich sed.
Perry
1
tl; dr: readist ein eingebautes Gerät und überspringt den Aufwand und die Buchhaltung, die mit dem Starten eines neuen Prozesses verbunden sind.
Henk Langeveld
0

Sie können schreibgeschützt varnamein einem Shell-Skript verwenden, aber zwei andere können Sie verwenden, ohne ein Shell-Skript zu schreiben.

Zum Beispiel:

Sie können varname=$(head -1)und varname=$(sed 1q)einfach als Befehl im Terminal verwenden, aber Sie müssen auch Ihr Argument angeben, dh welche Dateien die oberste Zeile sind, auf die Sie sich beziehen, dh varnam=$(head -1 file1).

Pranav Tyagi
quelle
2
Natürlich können Sie auch read varnameaußerhalb eines Shell-Skripts verwenden. Versuch es! Es gibt nur sehr wenige Dinge, die Sie in einem Skript tun können, die Sie nicht an einer Eingabeaufforderung in der Sh-Familie "sh" ausführen können (ob sie sehr nützlich sind, ist eine andere Sache).
Perry