Bonne façon
Normalement, vous ne pouvez pas faire cela avec grep, mais vous pouvez utiliser d'autres outils. AWK a déjà été mentionné, mais vous pouvez également utiliser sed
, comme ceci:
sed -e '1p' -e '/youpattern/!d'
Comment ça fonctionne:
L'utilitaire Sed fonctionne sur chaque ligne individuellement, en exécutant des commandes spécifiées sur chacune d'entre elles. Vous pouvez avoir plusieurs commandes, en spécifiant plusieurs -e
options. Nous pouvons ajouter à chaque commande un paramètre de plage spécifiant si cette commande doit être appliquée à une ligne spécifique ou non.
"1p" est une première commande. Il utilise une p
commande qui affiche normalement toutes les lignes. Mais nous le préfixons avec une valeur numérique qui spécifie la plage à laquelle il doit être appliqué. Ici, nous utilisons 1
ce qui signifie première ligne. Si vous souhaitez imprimer plus de lignes, vous pouvez utiliser x,yp
où x
est la première ligne pour imprimer, y
est la dernière ligne pour imprimer. Par exemple, pour imprimer les 3 premières lignes, vous utiliseriez1,3p
La commande suivante est celle d
qui supprime normalement toutes les lignes du tampon. Avant cette commande, nous mettons yourpattern
entre deux /
caractères. C’est l’autre façon (en premier lieu de spécifier les lignes que nous avons utilisées avec la p
commande) d’adressage des lignes sur lesquelles la commande devrait être exécutée. Cela signifie que la commande ne fonctionnera que pour les lignes qui correspondent yourpattern
. Sauf que nous utilisons !
caractère avant d
commande qui inverse sa logique. Alors maintenant, toutes les lignes qui ne correspondent pas au motif spécifié seront supprimées .
À la fin, sed imprimera toutes les lignes laissées en mémoire tampon. Mais nous avons supprimé les lignes qui ne correspondent pas du tampon afin que seules les lignes correspondantes soient imprimées.
Pour résumer: nous imprimons la 1ère ligne, puis nous supprimons toutes les lignes qui ne correspondent pas à notre modèle d'entrée. Reste des lignes sont imprimées (donc seulement des lignes qui font correspondre au modèle).
Problème de première ligne
Comme mentionné dans les commentaires, cette approche pose problème. Si le motif spécifié correspond également à la première ligne, il sera imprimé deux fois (une fois par p
commande et une fois en raison d'une correspondance). Nous pouvons éviter cela de deux manières:
Ajout de 1d
commande après 1p
. Comme je l'ai déjà mentionné, la d
commande supprime les lignes du tampon et nous spécifions sa plage par le numéro 1, ce qui signifie qu'elle supprimera uniquement la 1ère ligne. Donc, la commande seraitsed -e '1p' -e '1d' -e '/youpattern/!d'
Utiliser la 1b
commande au lieu de 1p
. C'est un tour b
Cette commande nous permet de passer à une autre commande spécifiée par une étiquette (certaines commandes peuvent ainsi être omises). Mais si cette étiquette n'est pas spécifiée (comme dans notre exemple), il saute simplement à la fin des commandes, ignorant le reste des commandes pour notre ligne. Donc, dans notre cas, la dernière d
commande ne supprimera pas cette ligne du tampon.
Exemple complet:
ps aux | sed -e '1b' -e '/syslog/!d'
Utiliser le point-virgule
Certaines sed
implémentations peuvent vous épargner une certaine frappe en utilisant un point-virgule pour séparer des commandes au lieu d'utiliser plusieurs -e
options. Donc, si vous ne vous souciez pas d'être portable, la commande le serait ps aux | sed '1b;/syslog/!d'
. Cela fonctionne au moins dans GNU sed
et les busybox
implémentations.
Façon folle
Voici cependant une façon assez folle de faire cela avec grep. Ce n'est certainement pas optimal, je le publie uniquement à des fins d'apprentissage, mais vous pouvez l'utiliser par exemple, si vous n'avez aucun autre outil dans votre système:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
Comment ça fonctionne
Tout d'abord, nous utilisons l' -n
option pour ajouter des numéros de ligne avant chaque ligne. Nous voulons numéroter toutes les lignes auxquelles nous correspondons .*
- n'importe quoi, même les lignes vides. Comme suggéré dans les commentaires, nous pouvons également faire correspondre '^', le résultat est le même.
Ensuite, nous utilisons des expressions régulières étendues pour pouvoir utiliser \|
un caractère spécial qui fonctionne comme OR. Nous faisons donc correspondre si la ligne commence par 1:
(première ligne) ou contient notre modèle (dans ce cas, son syslog
).
Problème de numéros de ligne
Maintenant, le problème est que nous obtenons ces numéros de ligne laids dans notre sortie. Si cela pose un problème, nous pouvons les supprimer avec cut
, comme ceci:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-d
option spécifie le délimiteur, -f
spécifie les champs (ou colonnes) que nous voulons imprimer. Nous voulons donc couper chaque ligne sur chaque :
caractère et imprimer uniquement la deuxième colonne et toutes les colonnes suivantes. Cela supprime efficacement la première colonne avec son délimiteur et c'est exactement ce dont nous avons besoin.
ack
sont si utiles, et pourquoiperl
passé sont montés en flèchesed
,awk
etc. en popularité: il est important pour les parties à résumer en un tout cohérent.