J'ai une commande qui génère des données vers 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 le tuyau sera utile ici). Et enfin, je voudrais que ce taux soit une valeur d'un paramètre sur une deuxième commande (disons command2 -t=${rate}
)
Cela semble difficile de mon côté; J'aimerais mieux savoir comment utiliser les pipes, grep, sed et ainsi de suite.
J'ai essayé beaucoup de combinaisons comme celle-ci, mais je suis confus:
$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}
Vous confondez deux types d'entrées très différents.
stdin
)Ils sont différents et utiles à des fins différentes. Certaines commandes peuvent accepter des entrées dans les deux sens, mais elles les utilisent généralement différemment. Prenons par exemple la commande wc
:
Passer l'entrée par stdin
:
ls | wc -l
Cela comptera les lignes dans la sortie de ls
Passer l'entrée par des arguments de ligne de commande:
wc -l $(ls)
Cela comptera les lignes dans la liste des fichiers imprimé par ls
Des choses complètement différentes.
Pour répondre à votre question, il semble que vous souhaitiez capturer le débit à partir de la sortie de la première commande, puis utiliser le débit comme argument de ligne de commande pour la deuxième commande. Voici une façon de procéder:
rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"
Explication du sed
:
s/pattern/replacement/
Consiste à remplacer un modèle^rate
) Suivi de deux caractères quelconques (..
), Suivis de 0 ou plusieurs chiffres, suivis d'un %
, suivi du reste du texte (.*
)\1
Dans le remplacement signifie le contenu de la première expression capturée dans \(...\)
, dans ce cas, les chiffres avant le signe %
-n
De la commande sed
signifie de ne pas imprimer les lignes par défaut. Le p
à la fin de la commande s///
Signifie imprimer la ligne en cas de remplacement. En bref, la commande n'imprimera quelque chose qu'en cas de correspondance.J'ai tendance à utiliser ceci:
command1 | xargs -I{} command2 {}
Passer la sortie de command1
via xargs en utilisant la substitution (les accolades) à command2
. Si command1 est find
assurez-vous d'utiliser -print0
et ajouter -0
à xargs
pour les chaînes terminées par null et xargs
appellera command2
pour 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 {}"
Pour simuler la sortie de command1
J'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
Nous obtenons donc la ligne que nous voulons hors de 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 à ce que "rate was "$(command1 | grep 'rate')
concatène automatiquement. Si cela ne fonctionne pas à cause des espaces, vous devriez pouvoir passer l'entrée comme ceci à la place:
$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "
La première tâche consiste à extraire le taux de cette ligne. Avec GNU grep (Linux non intégré ou Cygwin), vous pouvez utiliser l'option -o
. La partie que vous voulez est celle qui ne contient que des chiffres et suivie d'un %
. Si vous ne voulez pas extraire le %
Lui-même, vous avez besoin d'une astuce supplémentaire: a assertion d'anticipation de largeur nulle , qui ne correspond à rien mais seulement si cela 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 commande s
, avec une expression régulière qui correspond à la ligne entière (commençant par ^
Et se terminant par $
), Avec le partie à conserver dans un groupe (\(…\)
). Remplacez la ligne entière par le contenu du ou des groupes à conserver. En général, passez l'option -n
Pour désactiver l'impression par défaut et placez le modificateur p
pour imprimer les lignes où il y a quelque chose à extraire (ici, il n'y a qu'une seule ligne donc ça n'a pas d'importance). Voir Renvoyer uniquement la partie d'une ligne après un motif correspondant et Extraire une expression régulière correspondant à 'sed' sans imprimer les caractères environnants pour plus d'astuces sed.
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 par défaut) et j'y 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}'
L'étape suivante, maintenant que vous avez extrait le taux, consiste à le passer en argument à command2
. L'outil pour cela est un commande susbtitution . Si vous placez une commande dans $(…)
(parenthèse dollar), 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; à moins que vous ne vouliez que cela se produise, mettez des guillemets doubles 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 retours à la ligne à la fin de la sortie sont supprimés).
command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"
J'utilise généralement `command` pour placer sa sortie comme argument d'une autre commande. Par exemple, pour trouver des ressources consommées par le processus foo sur freebsd, il faudra:
procstat -r `pgrep -x foo`
Ici, pgrep est utilisé pour extraire le PID du processus foo qui est passé à la commande procstat qui attend le PID du processus comme argument.
Vous pouvez utiliser grep
et c'est PCRE - Perl Compatible Regular Expressions. Cela vous permet d'utiliser un lookbehind pour faire correspondre la valeur du taux, sans inclure la chaîne "taux" dans vos résultats lors de la recherche.
$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10
Le grep
ci-dessus fonctionne comme suit:
-o
Renverra uniquement ce que nous recherchons, \d+
, Qui sont les chiffres entre les parenthèses.-P
Active la fonction PCRE de grep(?<=^rate \()
Ne renverra que les chaînes commençant par "rate ("Pour saisir la valeur de "rate", vous pouvez exécuter command1
Comme ceci:
$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'
Ensuite, pour votre 2e commande, vous utiliseriez simplement cette variable.
$ command2 -t=${rate}
Vous pourriez devenir chic et faire tout cela sur une seule ligne:
$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')
Cela exécutera command1 à l'intérieur du bloc d'exécution $(..)
, prendra ses résultats et les inclura dans le commutateur -t=..
De command2.