Kann bash das gleiche FIFO aus zwei separaten Befehlen verbrauchen?

703
Andrew

Ich habe eine riesige Datenquelle, die ich mithilfe einiger greps filtere.

Im Grunde mache ich gerade was:

#!/bin/bash param1='something' param2='another' param3='yep' echo $(avro-read /log/huge_data | grep $param1 | grep "$param2-" | grep $param3 | wc -l) / $(avro-read /log/ap/huge_data | grep $param1 | grep -v "$param2-" | grep $param3 | wc -l) | bc -l 

Beachten Sie, wie ich meistens zweimal die gleiche Filterung vornehme (eine einzige Differenz beim zweiten Mal), die Anzahl der einzelnen Werte nehme und das Endergebnis dividiere. Dies ist definitiv eine harte Angelegenheit, aber ich möchte es etwas beschleunigen und die anfängliche Filterung nur einmal durchführen, ohne eine temporäre Datei zu verwenden.

Ich habe versucht, ein Fifo zu verwenden, aber ich bin nicht sicher, ob es möglich ist, zwei Prozesse in einem Skript zu lesen und einen dritten Prozess zu "warten", bis beide fertig sind, um das Endergebnis zu berechnen. Ich habe auch nachgesucht tee, aber nicht sicher, wie ich die resultierenden Unterprozesse synchronisieren soll.

BEARBEITEN: Dieses Problem wurde von mir mithilfe von https://superuser.com/a/561248/43649 behoben. Als Antwort wurde jedoch ein anderer Vorschlag ausgewählt.

5
Nein; Sobald ein Prozess Daten aus dem FIFO liest, sind diese Daten verschwunden und werden vom anderen Prozess nicht gesehen. chepner vor 11 Jahren 0

3 Antworten auf die Frage

2
Dennis

Wenn Sie nur vermeiden möchten, temporäre Dateien zu erstellen (oder die Ausgabe von grep in einer Variablen zu speichern), können Sie sie einer for-Schleife wie folgt zuführen:

#!/bin/bash  IFS=$'\n' yay=0 nay=0  for line in `avro-read /log/huge_data | grep $param1 | grep $param3`; do [[ $line =~ $param2- ]] && yay=$(($yay + 1)) || nay=$(($nay + 1)) done  echo $yay / $nay \* 100 | bc -l  unset IFS 

Ich habe in Ihrer Selbstantwort eine modifizierte Version des Ansatzes erstellt, für die keine temporären Dateien erforderlich sind:

#!/bin/bash  (avro-read /log/huge_data | grep $param1 | grep $param3 | tee \ >(echo yay=`grep -c "$param2-"`) \ >(echo nay=`grep -vc "$param2-"`) \ >/dev/null | cat ; echo 'echo $yay / $nay \* 100 | bc -l') | sh 

Die Ausgabe der einzelnen grep -cBefehle und des echoBefehls wird als gedruckt

yay=123 nay=456 echo $yay / $nay \* 100 | bc -l 

Rennbedingungen vermeiden 1 . Piping zum shAusführen der gedruckten Befehle.

1 Je nachdem, welcher grep -cBefehl zuerst beendet wird, wird die erste Ausgabezeile gedruckt.

Super cooler Weg, um die Daten zu durchlaufen. Andrew vor 11 Jahren 0
Großartig - das ist ein Trick, den man sich merken muss, um die Werte aus den Prozessersetzungen herauszuholen :) mpy vor 11 Jahren 0
Beeindruckend! Super coole Art, es zu tun. Danke für die Anpassung meiner Antwort! Es gibt definitiv viel zu lernen. Andrew vor 11 Jahren 0
1
Andrew

Am Ende habe ich das so gelöst:

#!/bin/bash param1='something' param2='another' param3='yep'  avro-read /log/huge_data | grep $param1 | grep $param3 \ | tee \ >(grep "$param2-" | wc -l | tr -d '\n' > has_count) \ >(grep -v "$param2-" | wc -l | tr -d '\n' > not_count) \ > /dev/null  echo $(cat has_count | tr -d '\n') '/' $(cat not_count | tr -d 'n') '* 100' | bc -l 

Anstatt sich auf eine FIFO- oder Temp-Datei zu verlassen, habe ich teeden Stream in zwei separate Prozesse aufgeteilt, die nur eine Zählung ausgeben! Auf diese Weise muss ich nicht versuchen, die beiden Prozesse zu synchronisieren, bevor ich die Zählungen teilen möchte.

Sie verwenden zwei temporäre Dateien ... mpy vor 11 Jahren 0
Sehr interessant! Ich habe in Ihre Antwort eine Änderung Ihres Ansatzes aufgenommen, für die keine temporären Dateien erforderlich sind. Dennis vor 11 Jahren 0
Mit "nicht auf eine temporäre Datei verlassen" meinte ich in diesem Fall eine temporäre Datei mit tatsächlichen Daten. In diesem Fall wird nur eine Nummer gespeichert. Andrew vor 11 Jahren 0
0
mpy

Hm, zshhat eine Funktion namens MULTIOS. Damit ist es möglich, einen Prozess an zwei FIFOs anzuschließen. Wenn das eine Option ist, hier eine kleine Demo:

#!/bin/zsh -f  setopt multios  mkfifo f1 f2 2> /dev/null  param1='something' param2='another' param3='yep'  { avro-read /log/huge_data | grep $param1 | grep $param3 } > f1 > f2 &  ( cat f1 | grep $param2 | wc -l > value1 ) &! value2=$(cat f2 | grep -v $param2 | wc -l)  print $(( 1. * $( cat value1 ) / $value2 ))  rm value1 

Ich konnte jedoch keinen Weg finden, um die Erstellung der temporären Datei value1zu umgehen, was wahrscheinlich von Dennis vermieden werden sollte. Aber vielleicht gefällt Ihnen diese Lösung trotzdem.