Das folgende Perl-Skript ( my.pl
) kann entweder aus der Datei in den Befehlszeilenargumenten oder aus STDIN lesen:
while (<>) {
print($_);
}
perl my.pl
liest aus STDIN, perl my.pl a.txt
liest aus a.txt
. Das ist sehr praktisch.
Sie fragen sich, ob es in Bash ein Äquivalent gibt?
/proc/$$/fd/0
und/dev/stdin
? Mir ist aufgefallen, dass Letzteres häufiger vorkommt und einfacher aussieht.-r
Ihrenread
Befehl zu ergänzen , damit er nicht versehentlich\
Zeichen frisst . Verwenden Siewhile IFS= read -r line
diese Option, um führende und nachfolgende Leerzeichen beizubehalten./bin/sh
Sie eine andere Shell alsbash
oder verwendensh
.Die vielleicht einfachste Lösung besteht darin, stdin mit einem zusammenführenden Umleitungsoperator umzuleiten:
Stdin ist Dateideskriptor Null. Das Obige sendet die Eingabe, die an Ihr Bash-Skript weitergeleitet wird, an less's stdin.
Lesen Sie mehr über die Umleitung von Dateideskriptoren .
quelle
<&0
In dieser Situation hat die Verwendung keinen Vorteil - Ihr Beispiel funktioniert mit oder ohne es gleich - anscheinend sehen Tools, die Sie innerhalb eines Bash-Skripts aufrufen, standardmäßig denselben Standard wie das Skript selbst (es sei denn, das Skript verwendet es zuerst).Hier ist der einfachste Weg:
Verwendung:
Um der Variablen stdin zuzuweisen , können Sie Folgendes verwenden:
STDIN=$(cat -)
oder einfach nur,STDIN=$(cat)
da kein Operator erforderlich ist (gemäß @ mklement0-Kommentar ).Versuchen Sie das folgende Skript, um jede Zeile aus der Standardeingabe zu analysieren :
Um aus der Datei oder stdin zu lesen (wenn kein Argument vorhanden ist), können Sie es erweitern auf:
Siehe: Wie lese ich stdin, wenn keine Argumente übergeben werden? bei Stackoverflow SE
quelle
[ "$1" ] && FILE=$1 || FILE="-"
zuFILE=${1:--}
. (Quibble: besser, alle Großbuchstaben Shell- Variablen zu vermeiden, um Namenskollisionen mit Umgebungsvariablen zu vermeiden .)${1:--}
ist POSIX-konform, so dass es in allen POSIX-wie Muscheln funktionieren soll. Was in all diesen Shells nicht funktioniert, ist die Prozessersetzung (<(...)
); es wird zum Beispiel in bash, ksh, zsh funktionieren, aber nicht in dash. Es ist auch besser,-r
Ihrenread
Befehl zu ergänzen , damit er nicht versehentlich\
Zeichen frisst . Stellen Sie vorIFS=
, um führende und nachfolgende Leerzeichen beizubehalten.echo
: Wenn eine Zeile aus oder besteht-e
, wird sie nicht angezeigt. Um dies zu beheben, müssen Sie Folgendes verwenden : . Ich habe es nicht in meine vorherige Bearbeitung aufgenommen. Zu oft werden meine Änderungen rückgängig gemacht, wenn ich diesen Fehler behebe .-n
-E
printf
printf '%s\n' "$line"
:(
--
ist nutzlos, wenn das erste Argument ist'%s\n'
IFS=
mitread
undprintf
anstelle von verwenden würdenecho
.:)
.Ich denke, das ist der einfache Weg:
- -
- -
quelle
read
liest aus stdin standardmäßig , so gibt es keine Notwendigkeit für< /dev/stdin
.Die
echo
Lösung fügt immer dann neue Zeilen hinzu, wennIFS
der Eingabestream unterbrochen wird. Die Antwort von @ fgm kann ein wenig geändert werden:quelle
read
das Verhalten bezogen haben: whileread
wird möglicherweise von den Zeichen in mehrere Token aufgeteilt. enthalten$IFS
, gibt es nur ein einzelnes Token zurück, wenn Sie nur einen einzelnen Variablennamen angeben (aber standardmäßig werden Leerzeichen und führende und nachfolgende Leerzeichen abgeschnitten).read
und$IFS
-echo
selbst zu und füge neue Zeilen ohne-n
Flag hinzu. "Das Dienstprogramm echo schreibt alle angegebenen Operanden, die durch einzelne Leerzeichen (` ') und gefolgt von einem Zeilenumbruchzeichen (`\ n') getrennt sind, in die Standardausgabe."\n
hinzufügenecho
: Perl's$_
enthält die Zeile, die\n
von der gelesenen Zeile endet , während Bashsread
dies nicht tut. (Wie @gniourf_gniourf jedoch an anderer Stelle ausführt, ist es robuster,printf '%s\n'
anstelle vonecho
) zu verwenden.Die Perl-Schleife in der Frage liest aus allen Dateinamenargumenten in der Befehlszeile oder aus der Standardeingabe, wenn keine Dateien angegeben sind. Die Antworten, die ich sehe, scheinen alle eine einzelne Datei oder Standardeingabe zu verarbeiten, wenn keine Datei angegeben ist.
Obwohl oft genau als UUOC (Useless Use of
cat
) verspottet , gibt es Zeiten, in denencat
das beste Werkzeug für den Job ist, und es ist fraglich, ob dies eines davon ist:Der einzige Nachteil dabei ist, dass eine Pipeline erstellt wird, die in einer Sub-Shell ausgeführt wird, also Dinge wie Variablenzuweisungen in der
while
Schleife außerhalb der Pipeline nicht zugänglich sind. Derbash
Weg dahin ist die Prozesssubstitution :Dies verlässt die
while
Schleife in der Haupt-Shell ausgeführt, sodass auf in der Schleife festgelegte Variablen außerhalb der Schleife zugegriffen werden kann.quelle
>>EOF\n$(cat "$@")\nEOF
. Schließlich ein Streitpunkt:while IFS= read -r line
ist eine bessere Annäherung an das, waswhile (<>)
in Perl funktioniert (behält führende und nachfolgende Leerzeichen bei - obwohl Perl auch die nachfolgenden Leerzeichen beibehält\n
).Perls Verhalten mit dem im OP angegebenen Code kann kein oder mehrere Argumente annehmen. Wenn ein Argument ein einzelner Bindestrich
-
ist, wird dies als stdin verstanden. Außerdem ist es immer möglich, den Dateinamen mit zu haben$ARGV
. Keine der bisher gegebenen Antworten ahmt Perls Verhalten in dieser Hinsicht wirklich nach. Hier ist eine reine Bash-Möglichkeit. Der Trick ist,exec
angemessen zu verwenden .Dateiname ist verfügbar in
$1
.Wenn keine Argumente angegeben werden, setzen wir künstlich
-
den ersten Positionsparameter. Wir durchlaufen dann die Parameter. Ist dies kein Parameter-
, leiten wir die Standardeingabe vom Dateinamen mit umexec
. Wenn diese Umleitung erfolgreich ist, schleifen wir mit einerwhile
Schleife. Ich verwende die StandardvariableREPLY
, und in diesem Fall müssen Sie nicht zurücksetzenIFS
. Wenn Sie einen anderen Namen möchten, müssen Sie diesen zurücksetzenIFS
(es sei denn, Sie möchten das natürlich nicht und wissen, was Sie tun):quelle
Genauer...
quelle
IFS=
und-r
zumread
Befehl wird sichergestellt, dass jede Zeile unverändert gelesen wird (einschließlich führender und nachfolgender Leerzeichen).Bitte versuchen Sie den folgenden Code:
quelle
read
ohneIFS=
und-r
und die Armen$line
ohne ihre gesunden Zitate zu sehen.read -r
Notation nicht. IMO, POSIX hat das falsch verstanden; Die Option sollte die spezielle Bedeutung für nachfolgende Backslashes aktivieren und nicht deaktivieren, damit vorhandene Skripte (von vor POSIX) nicht beschädigt werden, da die-r
weggelassen wurden. Ich stelle jedoch fest, dass es Teil von IEEE 1003.2 1992 war, der frühesten Version des POSIX-Shell- und Utilities-Standards, aber es wurde bereits damals als Ergänzung markiert, sodass es um längst vergangene Möglichkeiten geht. Ich bin nie in Schwierigkeiten geraten, weil mein Code nicht verwendet wird-r
. Ich muss Glück haben. Ignoriere mich dabei.-r
dies Standard sein sollte. Ich bin damit einverstanden, dass dies in Fällen unwahrscheinlich ist, in denen die Nichtverwendung zu Problemen führt. Fehlerhafter Code ist jedoch fehlerhafter Code. Meine Bearbeitung wurde zuerst durch diese schlechte$line
Variable ausgelöst , die ihre Anführungszeichen stark verfehlt hat. Ich habe das behoben,read
während ich dabei war. Ich habe das nicht behoben,echo
weil dies die Art von Bearbeitung ist, die zurückgesetzt wird.:(
.Code
${1:-/dev/stdin}
wird nur das erste Argument verstehen, also wie wäre es damit?quelle
Ich finde keine dieser Antworten akzeptabel. Insbesondere behandelt die akzeptierte Antwort nur den ersten Befehlszeilenparameter und ignoriert den Rest. Das Perl-Programm, das es zu emulieren versucht, verarbeitet alle Befehlszeilenparameter. Die akzeptierte Antwort beantwortet also nicht einmal die Frage. Andere Antworten verwenden Bash-Erweiterungen, fügen unnötige 'cat'-Befehle hinzu, funktionieren nur für den einfachen Fall, dass Eingabe zu Ausgabe wiederholt wird, oder sind einfach unnötig kompliziert.
Ich muss ihnen jedoch etwas Anerkennung zollen, weil sie mir einige Ideen gegeben haben. Hier ist die vollständige Antwort:
quelle
Ich habe alle oben genannten Antworten kombiniert und eine Shell-Funktion erstellt, die meinen Anforderungen entspricht. Dies ist von einem Cygwin-Terminal meiner 2 Windows 10-Computer, auf dem sich ein freigegebener Ordner befand. Ich muss in der Lage sein, Folgendes zu handhaben:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Wenn ein bestimmter Dateiname angegeben ist, muss beim Kopieren derselbe Dateiname verwendet werden. Wenn der Eingabedatenstrom durchgeleitet wurde, muss ich einen temporären Dateinamen mit der Stunde, Minute und Sekunde generieren. Der freigegebene Hauptordner enthält Unterordner der Wochentage. Dies dient organisatorischen Zwecken.
Siehe, das ultimative Skript für meine Bedürfnisse:
Wenn es eine Möglichkeit gibt, dies weiter zu optimieren, würde ich gerne wissen.
quelle
Das Folgende funktioniert mit Standard
sh
(Getestet mitdash
auf Debian) und ist gut lesbar, aber das ist Geschmackssache:Details: Wenn der erste Parameter nicht leer ist, dann
cat
diese Datei, sonstcat
Standardeingabe. Dann wird die Ausgabe der gesamtenif
Anweisung von der verarbeitetcommands_and_transformations
.quelle
cat "${1:--}" | any_command
. Das Lesen und Wiedergeben von Shell-Variablen funktioniert möglicherweise für kleine Dateien, ist jedoch nicht so gut skalierbar.[ -n "$1" ]
kann vereinfacht werden[ "$1" ]
.Dieser ist einfach auf dem Terminal zu bedienen:
quelle
Wie wäre es mit
quelle
cat
wird in die Befehlszeile eingefügt. Die Befehlszeile hat eine maximale Größe. Auch dies wird nicht Zeile für Zeile, sondern Wort für Wort gelesen.