Viele Befehlszeilenprogramme können ihre Eingabe entweder über eine Pipe oder als Dateinamenargument verwenden. Bei langen Shell-Skripten ist das Starten der Kette mit einem cat
besser lesbar, insbesondere wenn der erste Befehl mehrzeilige Argumente benötigt.
Vergleichen Sie
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
und
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
Ist die letztere Methode weniger effizient? Wenn ja, ist der Unterschied ausreichend, um zu berücksichtigen, ob das Skript beispielsweise einmal pro Sekunde ausgeführt wird? Der Unterschied in der Lesbarkeit ist nicht groß.
shell-script
performance
pipe
cat
Tshepang
quelle
quelle
cat
. Aber ich denke , die größere Frage ist hier die Lesbarkeit des Codes , die häufig ist eine Priorität über die Leistung. Wenn schneller eigentlich schöner geschrieben werden kann , warum nicht? Das Hervorheben des Problemscat
führt in der Regel dazu, dass der Benutzer die Pipelines und Prozesse im Allgemeinen besser versteht. Die Mühe lohnt sich, damit sie das nächste Mal verständlichen Code schreiben.cat
. Calebs Hinweis zur Verwendung von Funktionen und Umleitung löst dies ebenfalls.)Antworten:
Die "endgültige" Antwort wird Ihnen natürlich von The Useless Use of
cat
Award gebracht .Wenn Sie cat instanziieren, damit Ihr Code anders gelesen wird, ist dies nur ein weiterer Prozess und eine weitere Reihe von Eingabe- / Ausgabestreams, die nicht benötigt werden. Normalerweise wird der eigentliche Stillstand in Ihren Skripten in ineffizienten Schleifen und aktueller Verarbeitung liegen. Auf den meisten modernen Systemen wird eine zusätzliche
cat
Leistung Ihre Leistung nicht beeinträchtigen, aber es gibtfastimmer eine andere Möglichkeit, Ihren Code zu schreiben.Wie Sie bemerken, können die meisten Programme ein Argument für die Eingabedatei akzeptieren. Es gibt jedoch immer die eingebaute Shell
<
, die überall dort verwendet werden kann, wo ein STDIN-Stream erwartet wird, der Ihnen einen Prozess erspart, indem Sie die Arbeit in dem Shell-Prozess ausführen, der bereits ausgeführt wird.Sie können sogar kreativ werden, wo Sie es schreiben. Normalerweise wird es am Ende eines Befehls platziert, bevor Sie Ausgabeumleitungen oder Pipes wie folgt angeben:
Das muss aber nicht so sein. Es kann sogar zuerst kommen. Zum Beispiel könnte Ihr Beispielcode so geschrieben werden:
Wenn die Lesbarkeit von Skripten Ihr Anliegen ist und Ihr Code so unübersichtlich ist, dass das Hinzufügen einer Zeile für
cat
das Verfolgen einfacher wird, gibt es andere Möglichkeiten, Ihren Code zu bereinigen. Eines, das ich häufig verwende, um Skripte später leichter herauszufinden, ist das Aufteilen von Pipes in logische Mengen und das Speichern in Funktionen. Der Skriptcode wird dann sehr natürlich und jeder Teil der Pipline ist leichter zu debuggen.Sie könnten dann fortfahren
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Eine Pipleline, die so liest, ist wirklich einfach zu befolgen, und die einzelnen Komponenten können problemlos in ihren jeweiligen Funktionen debuggt werden.quelle
<file
das vor dem Befehl kommen könnte. Dies löst alle meine Probleme!<file
kann überall in der Befehlszeile stehen:<file grep needle
odergrep <file needle
odergrep needle <file
. Die Ausnahme bilden komplexe Befehle wie Schleifen und Gruppierungen. dort muss die umleitung nach dem schließen kommendone
/}
/)
/ etc. @Caleb Dies gilt für alle Bourne / POSIX-Shells. Und ich stimme nicht zu, dass es hässlich ist.$(cat /some/file)
mit$(< /some/file)
, was das Gleiche tut , vermeidet aber einen Prozess Laichen.$(< /some/file)
Portabilität eingeschränkt ist. Es funktioniert in bash, aber nicht in BusyBox ash oder FreeBSD sh. Funktioniert wahrscheinlich auch nicht im Armaturenbrett, da die letzten drei Muscheln alle enge Verwandte sind.Hier ist eine Zusammenfassung einiger der Nachteile von:
Über
$file
. Im Falle voncat
ist das immer ein Problem, mit Ausnahme vonzsh
; Bei der Umleitung ist dies nur ein Problem fürbash
oderksh88
, bei einigen anderen Shells nur dann, wenn sie interaktiv sind (nicht in Skripten).cmd
es eingebaut ist, dies in einigen Shells sogar 2 Prozesse sindbash
.cat
es eingebaut ist, wird auch ein zusätzlicher Befehl ausgeführt (und natürlich geladen und initialisiert (und auch die Bibliotheken, mit denen er verknüpft ist)).cat
undcmd
-Prozesse abwechselnd einplanen und den Pipe-Puffer ständig auffüllen und leeren muss. Auch wenncmd
tut1GB
großeread()
Systemaufrufe zu einer Zeit, wird die Steuerung muß hin und her zwischen gehencat
undcmd
weil ein Rohr kann nicht mehr als ein paar Kilobyte Daten zu einer Zeit halten.cmd
s (wiewc -c
) können einige Optimierungen vornehmen, wenn ihr stdin eine reguläre Datei ist, mit der sie nichtscat | cmd
anfangen können, da ihr stdin dann nur eine Pipe ist. Mitcat
und einer Pipe bedeutet dies auch, dass sie nichtseek()
in der Datei enthalten sein können. Bei Befehlen wietac
odertail
macht dies einen großen Unterschied in der Leistung, da bei diesen Befehlencat
die gesamte Eingabe im Speicher abgelegt werden muss.cat $file
und sogar die korrektere Versioncat -- "$file"
funktionieren nicht richtig für bestimmte Dateinamen wie-
(--help
oder alles, was mit beginnt,-
wenn Sie die vergessen--
). Wenn man darauf bestehtcat
, sollte man auscat < "$file" | cmd
Gründen der Zuverlässigkeit wahrscheinlich stattdessen verwenden.$file
es nicht zum Lesen geöffnet werden kann (Zugriff verweigert, existiert nicht ...),< "$file" cmd
wird eine konsistente Fehlermeldung (von der Shell) gemeldet und nicht ausgeführtcmd
, währendcat $file | cmd
es weiterhin ausgeführt wirdcmd
, wobei die Standard-ID wie eine leere Datei aussieht. Das bedeutet auch, dass in Sachen< file cmd > file2
,file2
wenn nicht geöffnet werdenfile
kann , nicht überladen wird .quelle
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Es gibt viele Parameter, die ins Bild kommen. Die Performance-Einbußen können von 0 bis 100% gehen. Ich denke jedenfalls nicht, dass die Strafe negativ sein kann.wc -c
ist ein ziemlich einzigartiger Fall, weil es eine Verknüpfung hat. Wenn Sie stattdessen tut ,wc -w
dann ist es vergleichbargrep
in meinem Beispiel (dh sehr wenig Verarbeitung - das ist die Situation , wo ‚<‘ kann einen Unterschied machen).wc -w
auf einer 1GB-Sparse-Datei im C-Gebietsschema unter Linux 4.9 und 64), dann finde ich, dass der cat-Ansatz 23% mehr Zeit in einem Multicore-System und 5% mehr Zeit in einem Core benötigt. Zeigt den zusätzlichen Aufwand an, der entsteht, wenn auf Daten von mehr als einem Kern zugegriffen wird. Sie erhalten möglicherweise unterschiedliche Ergebnisse, wenn Sie die Größe der Pipe ändern, unterschiedliche Daten verwenden, echte E / A-Vorgänge verwenden und splice () verwenden. Dies alles bestätigt, dass viele Parameter im Bild enthalten sind und das wird auf jedencat
fall nicht helfen.wc -w
der Unterschied ungefähr 2% ... 15%, wenn es sich um ein einfaches Grep handelt. Dann, seltsamerweise, wenn es auf einer NFS-Dateifreigabe ist, ist es tatsächlich 20% schneller zu lesen, wenn es voncat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Weird ...Das Platzieren
<file
am Ende einer Pipeline ist weniger lesbar alscat file
am Anfang. Natürliches Englisch liest von links nach rechts.Den
<file
Start der Pipeline zu setzen ist auch weniger lesbar als cat, würde ich sagen. Ein Wort ist besser lesbar als ein Symbol, insbesondere ein Symbol, das in die falsche Richtung weist.Mit wird
cat
dascommand | command | command
Format beibehalten .quelle
<
Once den Code weniger lesbar macht, da dadurch die Syntaxkonsistenz einer Multipipeline zerstört wird.<
wie diesen erstellen :alias load='<'
und dann zload file | sed ...
. Aliase können nach der Ausführung in Skripten verwendet werdenshopt -s expand_aliases
.Eine Sache, die die anderen Antworten hier offenbar nicht direkt angesprochen haben, ist, dass eine solche Verwendung
cat
nicht "nutzlos" ist in dem Sinne, dass "ein irrelevanter Katzenprozess entsteht, der keine Arbeit leistet". Es ist in dem Sinne nutzlos, dass "ein Katzenprozess erzeugt wird, der nur unnötige Arbeit leistet".Im Fall dieser beiden:
Die Shell startet einen sed-Prozess, der von somefile oder stdin (bzw.) liest, und führt dann eine Verarbeitung durch - sie liest, bis sie eine neue Zeile erreicht, ersetzt das erste 'foo' (falls vorhanden) in dieser Zeile durch 'bar' und druckt dann diese Linie zu stdout und Schleifen.
Im Falle des:
Die Muschel erzeugt einen Katzenprozess und einen Sed-Prozess und verdrahtet den Standard der Katze mit dem Standard der Sed. Der cat-Prozess liest einen Teil von mehreren Kilo- oder vielleicht Megabyte aus der Datei und schreibt ihn dann in seine Standardausgabe, in der der sed-Befehl wie im obigen zweiten Beispiel von dort abhebt. Während sed diesen Chunk verarbeitet, liest cat einen weiteren Chunk und schreibt ihn in seine Standardausgabe, damit sed als nächstes daran arbeiten kann.
Mit anderen Worten, die zusätzliche Arbeit, die durch das Hinzufügen des
cat
Befehls erforderlich ist, ist nicht nur die zusätzliche Arbeit, einen zusätzlichencat
Prozess zu erzeugen , sondern auch die zusätzliche Arbeit, die Bytes der Datei zweimal statt einmal zu lesen und zu schreiben. In der Praxis und auf modernen Systemen macht dies keinen großen Unterschied - es kann dazu führen, dass Ihr System einige Mikrosekunden unnötiger Arbeit leistet. Wenn es sich jedoch um ein Skript handelt, das Sie verteilen möchten, möglicherweise an Personen, die es auf Computern verwenden, die bereits nicht ausreichend ausgelastet sind, können sich einige Mikrosekunden über viele Iterationen summieren.quelle
cat
.cat
geteilt durch die ms ohnecat
in Prozent (zB 264 ms / 216 ms = 1.22 = 122% = 22% langsamer mitcat
)