Wie verwendet man die Ausgabeumleitung in Kombination mit here-documents und cat?

56

Angenommen, ich habe ein Skript, das ich an einen anderen Befehl weiterleiten oder in eine Datei umleiten möchte ( shfür die Beispiele an). Angenommen, ich verwende bash.

Ich könnte es tun mit echo:

echo "touch somefile
echo foo > somefile" | sh

Ich könnte auch fast dasselbe tun mit cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

Aber wenn ich "EOF" durch "EOF | sh" ersetze, denkt es nur, dass es ein Teil des Heredocs ist.

Wie kann ich dafür sorgen, dass der catText von stdin ausgegeben und dann an eine beliebige Stelle weitergeleitet wird?

strugee
quelle
touchist es denn da, was genau willst du? wird nur die eingabedatei gelesen und mit stdout zu einer anderen umgeleitet?
Rahul Patil
2
@ RahulPatil natürlich ist es nutzlos. Ich wollte nur ein Beispiel mit mehr als einer Zeile, um den Heredoc besser zu veranschaulichen. Und schauen Sie sich das Beispiel an echo- ich habe mich gefragt, was das Äquivalent dazu wäre cat.
Strugee
In Ihrem Beispiel wird ein shSkript aus mehreren Zeichenfolgen erstellt und direkt an übergeben sh. Ich habe festgestellt, dass Ihr Q die Textausgabe mehrerer Befehle, einschließlich eines HERE-Dokuments, direkt an einen Befehl übergeben möchte. Welches ist, was Ashs Antwort 2. Beispiel tut.
Dave X

Antworten:

91

Hierfür gibt es mehrere Möglichkeiten. Das einfachste ist wahrscheinlich das:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

Eine andere, meiner Meinung nach schönere Syntax:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

Das funktioniert auch, aber ohne die Subshell:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

Weitere Variationen:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

Oder:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

Übrigens erwarte ich, dass die Verwendung von catin Ihrer Frage ein Platzhalter für etwas anderes ist. Wenn nicht, nehmen Sie es wie folgt aus:

sh <<EOF
touch somefile
echo foo > somefile
EOF

Was könnte dazu vereinfacht werden:

sh -c 'touch somefile; echo foo > somefile'

oder:

sh -c 'touch somefile
echo foo > somefile'

Ausgabe umleiten statt leiten

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

Verwenden Sie cat, um das Äquivalent zu erhalten echo test > out:

cat >out <<EOF
test
EOF

Mehrere Dokumente hier

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

Dies erzeugt die Ausgabe:

hi
---
there

Folgendes ist los:

  • Die Shell sieht das ( ... )und führt die darin enthaltenen Befehle in einer Subshell aus.
  • Die Katze und das Echo sind einfach genug. Der cat <&3Befehl zum Ausführen von cat mit dem Dateideskriptor (fd) 0 (stdin), umgeleitet von fd 3; Mit anderen Worten, die Eingabe von fd 3 wird ausgeglichen.
  • Bevor das (...)gestartet wird, sieht die Shell, dass die beiden hier aufgeführten Dokumente umgeleitet werden, und ersetzt fd 0 ( <<EOF) und fd 3 ( 3<<EOF2) durch die Leseseite von Pipes
  • Sobald der anfängliche Befehl gestartet ist, liest die Shell ihren stdin, bis EOF erreicht ist, und sendet diesen an die Write-Seite der ersten Pipe
  • Als Nächstes wird dasselbe mit EOF2 und der Schreibseite der zweiten Pipe durchgeführt
Asche
quelle
Können Sie anhand des vorletzten Beispiels ein Beispiel mit stdout-Umleitung anstelle von Piping angeben?
Strugee
Ich habe die Antwort mit einem Redirect-Beispiel bearbeitet. Ist dies das Formular, das Sie bearbeiten wollten? Wenn nicht, können Sie einfach die erste Zeile dieses Teils angeben, um dies zu klären?
Asche
1
Es kann hilfreich sein zu verstehen, wie die Shell dies verarbeitet. Wenn die Befehlszeile ausgewertet wird und die << EOF gefunden wird, wird von der Standardeingabe gelesen, bis entweder eine Zeile mit nur EOF gefunden wird oder das Ende der Eingabe. Alles andere in der ursprünglichen Befehlszeile, das noch nicht verarbeitet wurde, wird dann weiter verarbeitet. So ist es zum Beispiel möglich, Folgendes zu tun: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >outund dann diesen Befehl mit zwei Hier-Blöcken in einer Reihe einzugeben.
Asche
Ihre Erklärung der Shell-Verarbeitung war interessant, aber über meinen Kopf hinweg :) Was ich wissen wollte, war, was das catÄquivalent von echo test > outwäre, mit einem Heredoc. Während Ihr gegebenes Beispiel eine Umleitung am Ende der Pipe hinzufügte.
Strugee
1
@OlivierDulac - Ich habe der Antwort das Multiple Heredoc-Beispiel hinzugefügt.
Asche
1

Ich möchte nur darauf hinweisen, dass die Verwendung meowgenauso gültig ist wie EOF.

Dieses Skript wird Meow!an eine Datei mit dem Namen angehängt cat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

Speichern unter catsund ausführbar machen mit chmod +x cats, dann ausführen mit ./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

Erläuterung:

  • cat <<meowist die hier verwendete Dokumentsyntax . Es weist das Skript an, den Textblock aufzunehmen, der dieser Zeile folgt, bis es auf die Zeichenfolge stößt meow. Der Inhalt wird dann ausgegeben (oder weitergeleitet).
  • >> catleitet zu der genannten Datei weiter cat.
  • Wenn Sie >anstelle von verwenden >>, wird die Datei überschrieben, anstatt sie anzufügen.
  • Meow!ist der Inhalt dieses Dokuments .
  • meowist die Endemarkierung für das Here-Dokument . Die Inhalte werden unter Verwendung von >>angehängt cat.

Piping sowohl zu stdout als auch zu einer Datei:

Für die von Ihnen angeforderte Verrohrung ist kein Dokument hier erforderlich.

catkann nicht gleichzeitig Text ausgeben und weitergeben, passt aber teeperfekt zu dem, wonach Sie fragen:

echo echo | tee tee

Dadurch wird sowohl die Zeichenfolge ausgegeben echoals auch echoin eine Datei mit dem Namen geschrieben tee.

Sie können die Ausgabe auch weiterleiten cat, wenn dies Teil der Anforderung ist, entweder mit:

echo echo | tee tee | cat </dev/stdin

Oder nur:

echo echo | tee tee | cat

Inhalt der Datei:

$ cat tee
echo
Alexander
quelle
1
Dies beantwortet die Frage nicht wirklich. Erstellt >auch keine Pipes, wie Ihre letzte Kugel andeutet.
Strugee
2
@strugee >kann Pipes erstellen, zshwenn derselbe fd mehrmals umgeleitet wird wie in echo foo >&1 > teeoder echo foo > tee | cat, wobei zshein internes implementiert wird tee, um die Ausgabe echosowohl an catdie teeDatei als auch an die Datei weiterzuleiten .
Stéphane Chazelas
Meine Antwort wurde aktualisiert, um die Frage besser beantworten zu können.
Alexander