Eine einzeilige Datei mit 2 tmp-Dateien (nicht das, was Sie wollen) wäre:
foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt
Mit bash könnten Sie jedoch versuchen:
diff <(foo | bar) <(baz | quux)
foo | bar | diff - <(baz | quux) # or only use process substitution once
Die 2. Version wird Sie deutlicher daran erinnern, welche Eingabe welche war, indem Sie
-- /dev/stdin
vs. ++ /dev/fd/63
oder etwas anstelle von zwei nummerierten fds anzeigen.
Nicht einmal eine Named Pipe wird im Dateisystem angezeigt, zumindest unter Betriebssystemen, in denen bash die Prozessersetzung mithilfe von Dateinamen implementieren kann /dev/fd/63
, um einen Dateinamen zu erhalten, den der Befehl öffnen und lesen kann, um tatsächlich aus einem bereits geöffneten Dateideskriptor zu lesen, den bash festgelegt hat vor dem Ausführen des Befehls. (dh bash verwendet pipe(2)
vor fork und dup2
leitet dann von der Ausgabe von quux
zu einem Eingabedateideskriptor für umdiff
auf fd 63 um.)
Auf einem System ohne "magisch" /dev/fd
oder/proc/self/fd
bash bash möglicherweise Named Pipes, um die Prozessersetzung zu implementieren, verwaltet sie jedoch im Gegensatz zu temporären Dateien zumindest selbst, und Ihre Daten werden nicht in das Dateisystem geschrieben.
Sie können überprüfen, wie bash die Prozessersetzung implementiert echo <(true)
, um den Dateinamen zu drucken, anstatt daraus zu lesen. Es wird /dev/fd/63
auf einem typischen Linux-System gedruckt . Oder um weitere Informationen darüber zu erhalten, welche Systemaufrufe bash verwendet, verfolgt dieser Befehl auf einem Linux-System Datei- und Dateideskriptorsystemaufrufe
strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
Ohne Bash könnten Sie eine Named Pipe erstellen . Verwenden Sie -
diese diff
Option, um eine Eingabe von STDIN zu lesen und die Named Pipe als die andere zu verwenden:
mkfifo file1_pipe.txt
foo|bar > file1_pipe.txt && baz | quux | diff file1_pipe.txt - && rm file1_pipe.txt
Beachten Sie, dass Sie mit dem Befehl tee nur einen Ausgang an mehrere Eingänge weiterleiten können:
ls *.txt | tee /dev/tty txtlist.txt
Der obige Befehl zeigt die Ausgabe von ls * .txt an das Terminal an und gibt sie an die Textdatei txtlist.txt aus.
Mit der Prozessersetzung können Sie jedoch tee
dieselben Daten in mehrere Pipelines einspeisen:
cat *.txt | tee >(foo | bar > result1.txt) >(baz | quux > result2.txt) | foobar
mkfifo a; cmd >a& cmd2|diff a -; rm a
pipeline1 | diff -u - <(pipeline2)
. Dann wird die Ausgabe Sie deutlicher daran erinnern, welche Eingabe welche war, indem Sie-- /dev/stdin
vs.++ /dev/fd/67
oder etwas anstelle von zwei nummerierten fds anzeigen.foo <( pipe )
) ändert das Dateisystem nicht. Die Pipe ist anonym ; Es hat keinen Namen im Dateisystem . Die Shell verwendet denpipe
Systemaufruf, um ihn zu erstellen, nichtmkfifo
. Verwenden Siestrace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
diese Option , um Datei- und Dateideskriptorsystemaufrufe zu verfolgen, wenn Sie sich selbst davon überzeugen möchten. Ist unter Linux/dev/fd/63
Teil des/proc
virtuellen Dateisystems. Es enthält automatisch Einträge für jeden Dateideskriptor und ist keine Kopie des Inhalts. Sie können das also nicht als "temporäre Datei" bezeichnen, es sei denn, esfoo 3<bar.txt
zähltIn bash können Sie Subshells verwenden, um die Befehlspipelines einzeln auszuführen, indem Sie die Pipeline in Klammern setzen. Sie können diesen dann <voranstellen, um anonyme Named Pipes zu erstellen, die Sie dann an diff übergeben können.
Beispielsweise:
Die anonymen Named Pipes werden von bash verwaltet, sodass sie automatisch erstellt und zerstört werden (im Gegensatz zu temporären Dateien).
quelle
Einige Personen, die auf dieser Seite ankommen, suchen möglicherweise nach einem zeilenweisen Unterschied, für den stattdessen ein Verwendungszweck verwendet werden sollte
comm
odergrep -f
sollte.Eine Sache, die hervorgehoben werden muss, ist, dass in allen Beispielen der Antwort die Unterschiede erst dann beginnen, wenn beide Streams beendet sind. Testen Sie dies mit zB:
Wenn dies ein Problem ist, können Sie es versuchen sd (stream diff), das weder sortiert (wie es
comm
tut) noch eine Prozessersetzung wie in den obigen Beispielen erfordert , um Größenordnungen oder Größenordnungen schneller alsgrep -f
und unterstützt unendliche Streams.Das von mir vorgeschlagene Testbeispiel würde so geschrieben sein
sd
:Aber der Unterschied ist das
seq 100
man sich sofort würdeseq 10
. Beachten Sie, dass, wenn einer der Streams a isttail -f
, der Diff nicht durch Prozessersetzung durchgeführt werden kann.Hier ist ein Blogpost, den ich über unterschiedliche Streams auf dem Terminal geschrieben habe
sd
.quelle