Befehl zum Ausgeben von Dateiinhalten an stdout?

28

Ich weiß, catdass dies möglich ist, aber der Hauptzweck besteht darin, Inhalte zu verketten und nicht nur anzuzeigen.

Ich weiß auch über lessund Bescheid more, aber ich suche etwas Einfaches ( keinen Pager ), das nur den Inhalt einer Datei an das Terminal ausgibt und das speziell dafür gemacht ist, wenn es so etwas gibt.

confused00
quelle
1
Tatsächlich verwenden Sie cat zu 99% zum Anzeigen von Dateien, anstatt etwas zu verketten.
LatinSuD
1
@LatinSuD - 100% der Zeit - catverkettet.
mikeserv
@mikeserv: Es kommt darauf an, was Sie unter einer Operation verstehen. Normaler Sprachgebrauch würde bedeuten, dass es mindestens einmal gemacht wird. Beim "Drucken" einer leeren Zeichenfolge werden keine Zeichen gedruckt. Es wäre fair zu sagen, dass es nichts druckt. Beim Computing werden jetzt a+b+czwei Additionen ausgeführt, und beim Computing awird nichts hinzugefügt. Ebenso beinhaltet das Ausführen cat fkeine Verkettung (obwohl dies das einzige ist, was "Verketten einer Sequenz einer Datei" bedeuten könnte).
Marc van Leeuwen
2
@mikeserv: Ich verstehe nicht, was du mit rein + raus meinst. Sicher catliest eine Datei und schreibt eine andere Datei (Stream), aber das bedeutet nicht, dass es sich um eine Verkettung handelt. Solltest du vielleicht meinen, dass cat fdas tatsächlich so cat - fist, ist das einfach nicht wahr.
Marc van Leeuwen
1
@ confused00: catsollte eigentlich verketten ( cat file1 file2verkettet beide Dateien zu stdout). Der Nebeneffekt ist jedoch, dass bei nur 1 Datei als Argument diese eine Datei an stdout ausgegeben wird (egal wo, entweder auf Ihrem Terminal oder auf etwas umgeleitet). Es wurde also kein anderer Befehl erstellt, um nur auf stdout auszugeben, wie er catexistierte und es einfach erlaubte. Deshalb möchten Sie verwenden cat.
Olivier Dulac

Antworten:

37

Das offensichtlichste ist cat. Schauen Sie sich aber auch headund an tail. Es gibt auch andere Shell utillities eine Datei Zeile für Zeile drucken: sed, awk, grep. Diese dienen jedoch dazu, den Dateiinhalt zu ändern oder in der Datei zu suchen.

Ich habe ein paar Tests durchgeführt, um abzuschätzen, welche die effektivste ist. Ich laufe alle durch, um stracezu sehen, welche die wenigsten Systemaufrufe gemacht haben. Meine Datei hat 1275 Zeilen.

  • awk: 1355 Systemaufrufe
  • cat: 51 Systemaufrufe
  • grep: 1337 Systemaufrufe
  • head: 93 Systemaufrufe
  • tail: 130 Systemaufrufe
  • sed: 1378 Systemaufrufe

Wie Sie sehen, catist es das schnellste und effektivste Programm , auch wenn es zum Verketten von Dateien entwickelt wurde. sed, awkund grepdruckte die Datei Zeile für Zeile, weshalb sie mehr als 1275 Systemaufrufe haben.

Chaos
quelle
8
Gute Idee, die Syscalls zu zählen!
Jan
1
+1, die Antwort ist genauer (über die Bedeutung der Katze), vollständiger (Alternativen) und recherchiert (Syscalls)
Olivier Dulac
23

Ich weiß, catdass dies möglich ist, aber der Hauptzweck besteht darin, Inhalte zu verketten und nicht nur anzuzeigen.

Der Zweck von catist genau das, eine Datei zu lesen und auf stdout auszugeben.

Jan
quelle
1
Aber cat --helpsagt „Concatenate Datei (en) oder Standardeingabe auf Standardausgabe“. Ich möchte nichts verketten
confused00
18
Ob Sie es glauben oder nicht, Katze ist genau das, wonach Sie suchen.
Jan
5
Nein, @ confused00, Jan hat recht. Die Sache ist - das Terminal ist stdout - Sie sehen? Sie readlink /dev/fd/1zum Beispiel - Sie sollten Ihre tty Namen dort bekommen , wenn bei einer Standardaufforderung. Sie müssen also die Eingabe mit der Ausgabe verknüpfen.
mikeserv
2
@mikeserv Ja, ich verstehe deinen Standpunkt, ich glaube, ich war zu sehr auf die Bedeutung von "verketten" fixiert.
confused00
3
Die Logik ist, dass das Drucken des Inhalts einer Datei nur ein Sonderfall für das sequentielle Drucken des Inhalts einer oder mehrerer Dateien ist.
zwol
10

Zuerst catschreibt auf die Standardausgabe, die nicht unbedingt ein Terminal ist, wenn auch catals Teil eines Befehls in einer interaktiven Shell eingegeben wurde. Wenn Sie wirklich etwas zum Schreiben in das Terminal benötigen, selbst wenn die Standardausgabe umgeleitet wird, ist dies nicht so einfach (Sie müssen angeben, welches Terminal verwendet wird, und es gibt möglicherweise nicht einmal ein Terminal, wenn der Befehl über ein Skript ausgeführt wird) könnte (ab) die Standardfehlerausgabe verwenden, wenn der Befehl nur ein Teil einer Pipeline ist. Aber da Sie angegeben haben, dass dies cattatsächlich der Fall ist, haben Sie wahrscheinlich nicht nach einer solchen Situation gefragt.

Wenn Sie beabsichtigen, das, was auf die Standardausgabe geschrieben ist, in eine Pipeline zu senden, ist using catfür den Useless Use of Cat Award berechtigt , da cat file | pipeline(wo pipelinefür eine Pipeline steht) dies effizienter durchgeführt werden kann <file pipeline. Aber auch aus Ihrer Formulierung schließe ich, dass dies nicht Ihre Absicht war.

Es ist also nicht so klar, worüber Sie sich Sorgen machen. Wenn die Eingabe catzu lang ist, können Sie einen ein- oder zweistelligen Alias ​​definieren (es gibt noch einige solche Namen, die in Standard-Unix nicht verwendet werden). Wenn Sie jedoch befürchten, catunnötige Zyklen zu verbringen, sollten Sie dies nicht tun .

Wenn es ein Programm gäbe null, das keine Argumente akzeptiert und nur die Standardeingabe in die Standardausgabe kopiert (das neutrale Objekt für Pipelines), könnten Sie tun, was Sie wollen <file null. Es gibt kein solches Programm, obwohl es einfach zu schreiben wäre (ein C-Programm mit nur einer einzeiligen mainFunktion kann den Job erledigen), aber ein Aufruf catohne Argumente (oder cat -wenn Sie explizit sein möchten) macht genau das.

Wenn es ein nocatProgramm gäbe , das genau ein Dateinamenargument verwendet, versucht, die Datei zu öffnen, sich darüber beschwert, wenn dies nicht möglich ist, und andernfalls von der Datei auf die Standardausgabe kopiert, dann ist dies genau das, wonach Sie gefragt haben. Es ist nur geringfügig schwieriger zu schreiben als null, da die Hauptarbeit darin besteht, die Datei zu öffnen, zu testen und möglicherweise zu beschweren (wenn Sie akribisch sind, möchten Sie möglicherweise auch einen Test einfügen, bei dem es genau ein Argument gibt, und sich ansonsten beschweren). Aber wieder einmal cat, jetzt mit einem einzigen Argument versehen, ist genau dies der Fall, sodass kein nocatProgramm erforderlich ist .

nocatWarum sollten Sie nach dem erfolgreichen Schreiben des Programms bei einem einzigen Argument stehen bleiben? Das Einwickeln des Codes in eine Schleife for(;*argp!=NULL;++argp)ist wirklich kein Aufwand, fügt der Binärdatei höchstens ein paar Maschinenanweisungen hinzu und vermeidet, sich über eine falsche Anzahl von Argumenten beschweren zu müssen (was viel mehr Anweisungen erspart). Voilà ist eine primitive Version von catverketteten Dateien. (Um ehrlich zu sein, müssen Sie es ein wenig optimieren, damit es sich ohne Argumente so verhält null.)

Natürlich catfügten sie im realen Programm ein paar Schnickschnack hinzu, weil sie es immer tun. Aber das Wesentliche ist, dass der Aspekt der "Verkettung" überhaupt catkeinen Aufwand kostet, weder für den Programmierer noch für die Maschine, die ihn ausführt. Die Tatsache, dass das Nichtvorhandensein solcher Programme catsubsumiert nullund nocaterklärt. Vermeiden Sie die Verwendung cateines einzelnen Arguments, wenn das Ergebnis in eine Pipeline eingeht, aber wenn es nur zum Anzeigen von Dateiinhalten auf dem Terminal verwendet wird, gibt selbst die von mir verlinkte Seite zu, dass dies eine nützliche Verwendung ist cat, zögern Sie also nicht.


Sie können testen , die catwirklich durch eine einfache Schleife um eine hypthetical implementiert nocatFunktionalität, durch den Aufruf catmit mehreren Dateinamen , unter denen ein ungültigen Name, nicht in der ersten Position: anstatt sofort beschwert , dass diese Datei nicht existiert, catzuerst die vorhergehenden Dumps gültige Dateien und beschwert sich dann über die ungültige Datei (zumindest verhält sich meine Katze so).

Marc van Leeuwen
quelle
7

Unter zshVersuch

<file

Ich glaube, es ist der kürzeste Weg, um eine Datei zu drucken. Es wird 'hidden' verwendet cat(oder morewenn stdout ein Terminal ist), aber der zum Drucken verwendete Befehl wird durch eine READNULLCMDVariable gesteuert , die Sie sicher direkt durch den Befehlsnamen oder sogar durch eine Funktion überschreiben können. So drucken Sie beispielsweise Dateien mit Zeilennummerierung:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
jimmij
quelle
5

POSIX definiert Katze als:

NAME

cat - Dateien verketten und drucken

ZUSAMMENFASSUNG

cat [-u] [datei ...]

BESCHREIBUNG

Das Dienstprogramm cat liest die Dateien nacheinander und schreibt ihren Inhalt in derselben Reihenfolge in die Standardausgabe.

Ich denke, verketten bedeutet hier, Dateien nacheinander zu lesen .

cuonglm
quelle
5

Ich weiß, dass dies eine Vergangenheitsfrage ist. Technisch gesehen ist das Ausdrucken des Inhalts einer Datei stdoutals Verkettung catsemantisch angemessen. Vergessen Sie nicht, dass printfsemantisch Daten formatiert und gedruckt werden sollen. Bash bietet auch eine Syntax zum Umleiten der Eingabe und Ausgabe von Dateien. Eine Kombination von diesen könnte dies erzeugen:

printf '%s' "$(<file.txt)"
James M. Lay
quelle
4
Abgesehen davon, dass cat file.txtes sich um einen Kreisverkehr handelt, entspricht der angezeigte Befehl nicht dem Befehl , da alle nachgestellten Zeilenumbrüche entfernt werden (der $(...)tut dies).
Marc van Leeuwen
+1, schöner Fang. Wusste ich nicht.
James M. Lay
3

Verwenden von integrierten bashFunktionen und Vermeiden der Erstellung von Unterprozessen:

{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFSwird nur auf den readBefehl angewendet , sorgen Sie sich also nicht um Ihre globalen IFSÄnderungen.

Schleife erforderlich, um Nullzeichen zu verarbeiten (danke an Stéphane Chazelas).

Diese Methode eignet sich nicht für große Dateien, da der Dateiinhalt zuerst in die Variable (also in den Speicher) gelesen wird. Übrigens habe ich versucht, eine 39-MB-Textdatei auf diese Weise zu drucken, und die Bash-Speichernutzung hat 5 MB nicht überschritten.

Es ist auch verdammt langsam und CPU ineffizient: Für die gleiche 39M-Datei dauerte es ~ 3 Minuten bei 100% Auslastung eines einzelnen Kerns.

Für große Dateien oder Binärdateien besser zu bedienen cat '/path/to/file'oder auch dd if='/path/to/file' bs=1Mwenn möglich.

Mikhail
quelle
1
Sehen Sie auch, pv -qwelche Linux-Version splice()welche für einige Arten von stdin / stdout verwenden kann, um die Leistung zu verbessern.
Stéphane Chazelas
1

Nur als Demonstration können Sie tun

cp foo /dev/stdout
weises Glück
quelle