it-swarm.com.de

Übergeben Sie die Ausgabe des vorherigen Befehls als Argument an next

Ich habe einen Befehl, der Daten an stdout ausgibt (command1 -p=aaa -v=bbb -i=4). Die Ausgabezeile kann folgenden Wert haben:

rate (10%) - name: value - 10Kbps

Ich möchte diese Ausgabe überprüfen, um diese 'Rate' zu speichern (ich denke, Pipe wird hier nützlich sein). Und schließlich möchte ich, dass diese Rate ein Wert eines Parameters in einem zweiten Befehl ist (sagen wir command2 -t=${rate})

Es scheint auf meiner Seite schwierig zu sein; Ich würde gerne besser wissen, wie man Pfeifen, Grep, Sed und so weiter benutzt.

Ich habe viele Kombinationen wie diese ausprobiert, aber ich bin verwirrt von diesen:

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}
140
Paul

Sie verwechseln zwei sehr unterschiedliche Arten von Eingaben.

  1. Standardeingabe (stdin)
  2. Kommandozeilenargumente

Diese sind unterschiedlich und für verschiedene Zwecke nützlich. Einige Befehle können auf beide Arten eingegeben werden, verwenden sie jedoch normalerweise unterschiedlich. Nehmen Sie zum Beispiel den Befehl wc:

  1. Eingabe von stdin übergeben:

    ls | wc -l
    

    Dadurch werden die Zeilen in der Ausgabe von ls gezählt

  2. Eingabe über Befehlszeilenargumente übergeben:

    wc -l $(ls)
    

    Dies zählt die Zeilen in der Liste der Dateien gedruckt von ls

Ganz andere Dinge.

Um Ihre Frage zu beantworten, möchten Sie die Rate aus der Ausgabe des ersten Befehls erfassen und dann die Rate als Befehlszeilenargument für den zweiten Befehl verwenden. Hier ist eine Möglichkeit, dies zu tun:

rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"

Erklärung des sed:

  • Der Befehl s/pattern/replacement/ Ersetzt ein Muster
  • Das Muster bedeutet: Die Zeile muss mit "rate" (^rate) Beginnen, gefolgt von zwei beliebigen Zeichen (..), Gefolgt von 0 oder mehr Ziffern, gefolgt von einem % , gefolgt vom Rest des Textes (.*)
  • \1 In der Ersetzung bedeutet den Inhalt des ersten Ausdrucks, der in \(...\) erfasst wird, also in diesem Fall die Ziffern vor dem Zeichen %
  • Das Flag -n Des Befehls sed bedeutet, dass standardmäßig keine Zeilen gedruckt werden. Das p am Ende des Befehls s/// Bedeutet, die Zeile zu drucken, wenn ein Ersatz vorhanden war. Kurz gesagt, der Befehl gibt nur dann etwas aus, wenn eine Übereinstimmung vorliegt.
159
janos

Ich neige dazu, dies zu verwenden:

command1 | xargs -I{} command2 {}

Übergeben Sie die Ausgabe von command1 Durch xargs unter Verwendung der Substitution (die geschweiften Klammern) an command2. Wenn command1 find ist, müssen Sie -print0 Verwenden und -0 Zu xargs für nullterminierte Zeichenfolgen hinzufügen, und xargs ruft command2 Für jede gefundene Sache.

In Ihrem Fall (und nehmen Sie die sed-Linie von @Janos):

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"
26

Um die Ausgabe von command1 Zu simulieren, verwende ich diese Echo-Anweisung:

$ echo -e "Foo\nrate (10%) - name: value - 10Kbps\nBar"
$ alias command1='echo -e "Blah\nrate (10%) - name: value - 10Kbps\nBlag"'

Ein kurzer Test:

$ command1
Blah
rate (10%) - name: value - 10Kbps
Blag

Das ist alles gut, also lasst es uns analysieren:

$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps

Also bekommen wir die gewünschte Zeile aus command1 Und geben sie an command2 Weiter:

$ alias command2='echo'
$ command2 -t="rate was "$(command1 | grep 'rate')
-t=rate was rate (10%) - name: value - 10Kbps

Ich erwarte, dass "rate was "$(command1 | grep 'rate') automatisch verkettet wird. Wenn dies aufgrund von Leerzeichen nicht funktioniert, sollten Sie die Eingabe stattdessen wie folgt übergeben können:

$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "
5
user56452

Versuchen Sie dies mit grep & pcre :

command | grep -oP '\$>\s+rate\s+\(\K[^\)]+'
4
Gilles Quenot

Die erste Aufgabe besteht darin, die Rate aus dieser Zeile zu extrahieren. Mit GNU grep (nicht eingebettetes Linux oder Cygwin)) können Sie die Option -o Verwenden. Der gewünschte Teil enthält nur Ziffern, gefolgt von einem % - Zeichen. Wenn Sie das % Nicht selbst extrahieren möchten, benötigen Sie einen zusätzlichen Trick: a Lookahead-Behauptung mit der Breite Null , die nur dann mit nichts übereinstimmt Auf nichts folgt %.

command1 -p=aaa -v=bbb -i=4 | grep -o -P '[0-9]+(?=%)'

Eine andere Möglichkeit ist die Verwendung von sed. Um einen Teil einer Zeile in sed zu extrahieren, verwenden Sie den Befehl s mit einem regulären Ausdruck, der der gesamten Zeile entspricht (beginnend mit ^ Und endend mit $) Teil, der in einer Gruppe beibehalten werden soll (\(…\)). Ersetzen Sie die gesamte Zeile durch den Inhalt der Gruppe (n), die beibehalten werden sollen. Übergeben Sie im Allgemeinen die Option -n, Um den Standarddruck zu deaktivieren, und setzen Sie den Modifikator p, um Zeilen zu drucken, in denen etwas extrahiert werden muss (hier gibt es eine einzelne Zeile, sodass dies keine Rolle spielt). Siehe Nur den Teil einer Zeile nach einem übereinstimmenden Muster zurückgeben und Extrahieren eines mit 'sed' übereinstimmenden regulären Ausdrucks, ohne die umgebenden Zeichen zu drucken für weitere sed-Tricks.

command1 -p=aaa -v=bbb -i=4 | sed 's/^.*rate(\([0-9]*\)%).*$/\1/'

Wieder flexibler als sed, ist awk. Awk führt Anweisungen für jede Zeile in einer kleinen imperativen Sprache aus. Es gibt viele Möglichkeiten, die Rate hier zu extrahieren. Ich wähle die zweiten Felder aus (Felder werden standardmäßig durch Leerzeichen begrenzt) und entferne alle darin enthaltenen Zeichen, die keine Ziffer sind.

command1 -p=aaa -v=bbb -i=4 | awk '{gsub(/[^0-9]+/, "", $2); print $2}'

Der nächste Schritt, nachdem Sie die Rate extrahiert haben, besteht darin, sie als Argument an command2 Zu übergeben. Das Werkzeug dafür ist ein Befehl susbtitution . Wenn Sie einen Befehl in $(…) (Dollar-Klammer) einfügen, wird seine Ausgabe in die Befehlszeile eingesetzt. Die Ausgabe des Befehls wird an jedem Leerzeichenblock in separate Wörter aufgeteilt, und jedes Wort wird als Platzhaltermuster behandelt. Wenn dies nicht geschehen soll, setzen Sie die Befehlsersetzung in doppelte Anführungszeichen: "$(…)". Bei doppelten Anführungszeichen wird die Ausgabe des Befehls direkt als einzelner Parameter verwendet (die einzige Umwandlung besteht darin, dass Zeilenumbrüche am Ende der Ausgabe entfernt werden).

command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
               sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"

Ich benutze im Allgemeinen "Befehl", um seine Ausgabe als Argument für einen anderen Befehl zu platzieren. Um beispielsweise die vom Prozess foo verbrauchte Ressource auf freebsd zu finden, gilt Folgendes:

procstat -r `pgrep -x foo`

Hier wird pgrep verwendet, um die PID des Prozesses foo zu extrahieren, die an den Befehl procstat übergeben wird, der die PID des Prozesses als Argument erwartet.

2
Vishal Sahu

Sie können grep verwenden und es handelt sich um PCRE - Perl-kompatible reguläre Ausdrücke. Auf diese Weise können Sie ein Lookbehind verwenden, um dem Wert von rate zu entsprechen, ohne die Zeichenfolge "rate" in Ihre Ergebnisse aufzunehmen, wenn Sie danach suchen.

Beispiel

$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10

Einzelheiten

Das obige grep funktioniert wie folgt:

  • -o Gibt nur das zurück, wonach wir suchen, \d+, Dies sind die Ziffern innerhalb der Parens.
  • -P Aktiviert die PCRE-Funktion von grep
  • (?<=^rate \() Gibt nur Zeichenfolgen zurück, die mit "rate (" beginnen).

befehl2

Um den Wert von "rate" abzufangen, können Sie command1 So ausführen:

$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'

Dann würden Sie für Ihren zweiten Befehl einfach diese Variable verwenden.

$ command2 -t=${rate}

Sie könnten Lust bekommen und das alles in einer Zeile machen:

$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')

Dadurch wird Befehl1 im Ausführungsblock $(..) ausgeführt, die Ergebnisse werden in den Schalter -t=.. Von Befehl2 aufgenommen.

1
slm