Combinez plusieurs commandes Unix en une seule sortie

9

Je dois rechercher dans nos journaux de messagerie une adresse e-mail spécifique. Nous conservons un fichier actuel nommé maillog ainsi qu'une valeur d'une semaine de fichiers .bz2 dans le même dossier. Actuellement, j'exécute les commandes suivantes pour rechercher le fichier:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

Existe-t-il un moyen de combiner les commandes grepet bzgrepen une seule sortie? De cette façon, je pouvais diriger les résultats combinés vers un seul e-mail ou un seul fichier.

Ben McCormack
la source

Réponses:

24

Une autre façon est

{ grep ...; bzgrep ...;} >file

&&a la difficulté de bzgrepne pas être exécuté en cas d' grepéchec.

Notez l'espace obligatoire après l'accolade ouvrante et le point-virgule après la dernière commande. Alternativement, vous pouvez utiliser la syntaxe de sous-shell (parenthèses au lieu d'accolades), qui n'est pas aussi difficile:

(grep ...; bzgrep ...) >file
geekosaure
la source
+1 pour la meilleure approche shell générale à ce problème. Le regroupement de shell est une fonctionnalité généralement sous-utilisée.
Phil Hollenback
2
Tu ne veux pas dire à la ()place de {}?
Ehtesh Choudhury
Sur arch linux, cela a fonctionné ()mais pas {}, dans tous les cas +1 car c'est ce dont j'avais besoin!
Chris Magnuson
11

bzgrep utilise automatiquement par défaut grep si un fichier n'est pas compressé en bzip. Ainsi, les éléments suivants devraient être suffisants:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

oh bien sûr, voici aussi ma solution obligatoire GNU Parallel :

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

ce qui pourrait être beaucoup plus rapide si vous vérifiez beaucoup de fichiers.

Phil Hollenback
la source
2

Voici une autre façon de le faire (en supposant que vous exécutez bash, ce que vous êtes probablement):

cat <(bzgrep ...) <(grep ...)

Ici bash alimente de manière transparente la sortie des commandes bzgrep et grep dans cat comme s'il s'agissait de fichiers (et ils sont en quelque sorte sous le capot, les détails dans l'url en bas).

Dans votre cas particulier, je recommanderais la solution de Phil, mais ce qui précède est une bonne astuce à garder dans votre sac.

Si vous êtes intéressé, vous pouvez en savoir plus ici: http://www.tldp.org/LDP/abs/html/process-sub.html

Drew Bloechl
la source
Ah oui, la réponse canonique pour «comment différenciez-vous la sortie de deux processus». Un bon truc à savoir.
Phil Hollenback
1

Au moment où j'écris ceci, la syntaxe de la réponse acceptée était incorrecte pour la plupart, sinon la totalité, des shells dérivés de Bourne, y compris bash. J'ai suggéré une modification en haut et accepté la réponse pour résoudre ce problème, mais j'étais également enclin à ajouter toutes ces autres informations, et cela aurait plutôt été une réécriture plutôt qu'une modification.

Vous pouvez utiliser des commandes composées:

{ grep ...; bzgrep ...; } >file

..ou sous-coques (notez les parenthèses au lieu des accolades):

(grep ...; bzgrep ...) >file

..pour regrouper les commandes. La méthode du sous-shell a une syntaxe plus agréable (plus tolérante au manque d'espace blanc et vous permet d'omettre le dernier point-virgule), mais elle bifurque un nouveau processus ou "fait semblant" en exécutant les commandes dans un environnement nettoyé. Les deux ont des avantages en fonction de ce que vous voulez faire, ce qui n'a pas d'importance ici, mais valent la peine d'être recherchés si vous voulez plus de compétences avec le shell.

Remarque: Vous pouvez également utiliser le pipelining avec ces astuces, vous pouvez donc faire quelque chose comme ceci:

{ grep ...; bzgrep ...; } | less

PS si vous ne se soucient pas de l'ordre des matches de votre production combinée, vous pouvez utiliser un seul &entre les deux commandes, comme suit: { grep ... & bzgrep ...; }. Ensuite, les deux commandes s'exécutent simultanément: le grepse lance et le shell le met en arrière-plan, puis le shell exécutera le bzgrep. (Mais il y a une petite mise en garde avec cela, l'explication impliquant la redirection de fichiers et la mise en mémoire tampon du flux de fichiers pouvant entraîner une très petite fraction des lignes dans le fichier de sortie à diviser / modifier: si vous verriez cela dépendrait de la façon dont votre grep, bzgrepet les libc stdio.hfonctions sont implémentées. Dans la plupart des implémentations, je pense que le fait de canaliser la commande avant de rediriger vers un fichier évitera le problème, vous pouvez donc faire { foo & bar; } | cat - >filecomme solution de contournement.)

mtraceur
la source
0

Vous pouvez lier les commandes avec && qui vous permettra d'exécuter chaque commande.

vous pouvez également ajouter >> textfile.txt à la fin de chaque commande et faire en sorte que la sortie frappe un fichier, puis l'envoyer par la poste.

Mike
la source
2
Comme l'a mentionné le geekosaure, && ne doit pas être utilisé ici car la valeur de retour de grep dépend de la découverte ou non de quelque chose. Si vous le faisiez grep ... && bzgrep ..., si grep n'avait pas de résultats, cela retournerait un échec et la commande s'arrêterait. >>est une bonne idée cependant, contrairement à >cela, il ajoutera une sortie à la fin d'un fichier existant.
DerfK
à droite j'avais oublié la condition de sortie empêchant la deuxième commande.
Mike