Passer le résultat de la commande précédente à next comme argument

119

J'ai une commande qui envoie des données à stdout ( command1 -p=aaa -v=bbb -i=4). La ligne de sortie peut avoir la valeur suivante:

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

Je veux grep cette sortie afin de stocker ce "taux" (je suppose que pipe sera utile ici). Et enfin, j'aimerais que ce taux soit la valeur d'un paramètre sur une deuxième commande (disons command2 -t=${rate})

Cela semble être délicat de mon côté; J'aimerais mieux savoir comment utiliser les pipes, grep, sed, etc.

J'ai essayé beaucoup de combinaisons comme celle-là, mais je suis confus:

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

Réponses:

144

Vous confondez deux types d'entrées très différents.

  1. Entrée standard ( stdin)
  2. Arguments en ligne de commande

Celles-ci sont différentes et sont utiles à des fins différentes. Certaines commandes peuvent accepter les entrées des deux manières, mais elles les utilisent généralement différemment. Prenons par exemple la wccommande:

  1. Passing input by stdin:

    ls | wc -l
    

    Cela comptera les lignes dans la sortie de ls

  2. Passing input par des arguments en ligne de commande:

    wc -l $(ls)
    

    Ceci comptera les lignes dans la liste des fichiers imprimés parls

Des choses complètement différentes.

Pour répondre à votre question, il semble que vous souhaitiez capturer le taux de la sortie de la première commande, puis utiliser le taux comme argument de ligne de commande pour la deuxième commande. Voici une façon de le faire:

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

Explication de la sed:

  • La s/pattern/replacement/commande est de remplacer un motif
  • Le motif signifie: la ligne doit commencer par "rate" ( ^rate) suivi de deux caractères ( ..), suivis de 0 ou plusieurs chiffres, suivis de a %, suivis du reste du texte ( .*)
  • \1dans le remplacement signifie le contenu de la première expression capturée à l'intérieur \(...\), donc dans ce cas les chiffres avant le %signe
  • Le -ndrapeau de la sedcommande signifie ne pas imprimer les lignes par défaut. La pfin de la s///commande signifie d’imprimer la ligne s’il y a eu remplacement. En bref, la commande n'imprimera quelque chose que s'il y a une correspondance.
janos
la source
13

J'ai tendance à utiliser ceci:

command1 | xargs -I{} command2 {}

Passez la sortie de command1xargs en utilisant la substitution (les accolades) à command2. Si command1 est findsûr d’utiliser -print0et d’ajouter -0à xargspour des chaînes terminées par null et xargsfera appel command2à chaque chose trouvée.

Dans votre cas (et en prenant la ligne sed de @Janos):

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"
Michael Anderson
la source
Cela garde les choses bien et pipe'd, c'est pourquoi j'aime ça.
Mateen Ulhaq
4

Pour simuler la sortie de command1J'utilise cette instruction echo:

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

Un test rapide:

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

C'est tout bon, alors analysons-le:

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

Donc, nous obtenons la ligne dont nous voulons sortir command1, passons cela dans command2:

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

Je m'attends "rate was "$(command1 | grep 'rate')à concaténer automatiquement. Si cela ne fonctionne pas à cause des espaces, vous devriez pouvoir passer l'entrée comme suit:

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

Essayez ceci en utilisant & :

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

La première tâche consiste à extraire le taux de cette ligne. Avec GNU grep (Linux non intégré ou Cygwin), vous pouvez utiliser cette -ooption. La partie que vous voulez est celle qui ne contient que des chiffres et suivie d'un %signe. Si vous ne souhaitez pas extraire le fichier% lui - même, vous avez besoin d'une astuce supplémentaire: une assertion de type lookahead de largeur nulle , qui ne correspond à rien, mais uniquement si rien n'est suivi de %.

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

Une autre possibilité est d'utiliser sed. Pour extraire une partie d'une ligne dans sed, utilisez la scommande, avec une expression rationnelle qui correspond à toute la ligne (en commençant par ^et se terminant par $), avec la partie à conserver dans un groupe ( \(…\)). Remplacez toute la ligne par le contenu du ou des groupes à conserver. En général, passez l' -noption pour désactiver l'impression par défaut et mettez le pmodificateur pour imprimer les lignes où il y a quelque chose à extraire (ici, il n'y a qu'une seule ligne, donc cela n'a pas d'importance). Voir Renvoyer uniquement la partie d'une ligne après un motif correspondant et Extraire une expression rationnelle associée à 'sed' sans imprimer les caractères environnants pour obtenir des astuces plus détaillées.

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

Encore plus flexible que sed, c'est génial. Awk exécute les instructions pour chaque ligne dans un petit langage impératif. Il existe de nombreuses façons d'extraire le taux ici; Je sélectionne les deuxièmes champs (les champs sont délimités par des espaces blancs par défaut) et supprime tous les caractères qui ne sont pas des chiffres.

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

La prochaine étape, maintenant que vous avez extrait le taux, consiste à le passer comme argument command2. L'outil pour cela est un susbtitution de commande . Si vous mettez une commande à l'intérieur $(…)(dollar-parenthesis), sa sortie est substituée dans la ligne de commande. La sortie de la commande est divisée en mots séparés à chaque bloc d'espaces, et chaque mot est traité comme un motif générique. sauf si vous voulez que cela se produise, utilisez des guillemets autour de la substitution de commande: "$(…)". Avec les guillemets doubles, la sortie de la commande est utilisée directement en tant que paramètre unique (la seule transformation est que les nouvelles lignes à la fin de la sortie sont supprimées).

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

Vous pouvez utiliser grepet c’est l’expression régulière compatible PCRE - Perl. Cela vous permet d'utiliser une recherche pour faire correspondre la valeur de taux, sans inclure la chaîne "taux" dans vos résultats lors de la recherche de contenu.

Exemple

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

Détails

Ce qui précède grepfonctionne comme suit:

  • -one renverra que ce que nous recherchons, à savoir \d+les chiffres dans les parenthèses.
  • -P active la fonction PCRE de grep
  • (?<=^rate \() ne renverra que les chaînes qui commencent par "rate ("

commande2

Pour saisir la valeur de "taux", vous pouvez exécuter command1comme suit:

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

Ensuite, pour votre 2e commande, vous utiliseriez simplement cette variable.

$ command2 -t=${rate}

Vous pourriez avoir envie de faire tout cela en une ligne:

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

Ceci exécutera commande1 à l'intérieur du $(..)bloc d'exécution, prendra ses résultats et les inclura dans le -t=..commutateur de commande2.

slm
la source
0

J'utilise généralement `command` pour placer sa sortie en tant qu'argument d'une autre commande. Par exemple, trouver la ressource consommée par le processus foo sur freebsd sera:

procstat -r `pgrep -x foo`

Ici, pgrep est utilisé pour extraire le PID du processus foo qui est transmis à la commande procstat qui attend le PID du processus en tant qu'argument.

Vishal Sahu
la source