web-dev-qa-db-fra.com

Convaincre grep de sortir toutes les lignes, pas seulement celles avec des correspondances

Disons que j'ai le fichier suivant:

$ cat test

test line 1
test line 2
line without the search Word
another line without it
test line 3 with two test words
test line 4

Par défaut, grep renvoie chaque ligne contenant le terme de recherche:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

Passer le --color paramètre à grep le fera surligner la partie de la ligne qui correspond à l'expression de recherche, mais il ne renvoie toujours que les lignes qui contiennent l'expression. Existe-t-il un moyen pour que grep affiche chaque ligne du fichier source, mais met en évidence les correspondances?

Mon terrible hack actuel pour accomplir cela (au moins sur les fichiers qui n'ont pas plus de 10000 lignes consécutives sans correspondance) est:

$ grep -B 9999 -A 9999 test test

Screenshot of the two commands

Si grep ne peut pas accomplir cela, existe-t-il un autre outil en ligne de commande qui offre les mêmes fonctionnalités? J'ai joué avec ack , mais il ne semble pas non plus avoir d'option pour cela.

127
Michael Mrozek
grep --color -E "test|$" yourfile

Ce que nous faisons ici, c'est la comparaison avec le $ motif et motif de test, évidemment $ n'a rien à colorier, donc seul le motif de test prend la couleur. Le -E active simplement la correspondance regex étendue.

Vous pouvez facilement en créer une fonction comme ceci:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
194
jacksonh
ack --passthru --color string file

pour Ubuntu et Debian, utilisez ack-grep au lieu d'ack

ack-grep --passthru --color string file

Une autre façon de faire cela correctement et de manière portable avec grep (en plus d'utiliser deux expressions rationnelles avec alternance comme dans la réponse acceptée) se fait via le modèle nul (et respectivement la chaîne nulle).
Cela devrait fonctionner aussi bien avec les deux -E et -F change depuis, selon la norme :

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

et

-F
    Match using fixed strings.
    [...] A null string shall match every line.

Il s'agit donc simplement de courir

grep -E -e '' -e 'pattern' infile

et respectivement

grep -F -e '' -e 'string' infile
13
don_crissti

J'ai la fonction suivante que j'utilise pour de telles choses:

highlight () {
    Perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

En interne, ça a l'air plutôt laid, c'est agréable et facile à utiliser, comme ceci:

cat some_file.txt | highlight some_Word

ou, pour un exemple un peu plus réel:

tail -f console.log | highlight ERROR

Vous pouvez changer les couleurs comme vous voulez (ce qui pourrait être difficile avec grep - je ne suis pas sûr) en changeant le 1 et 31 et 43 (après \e[) à différentes valeurs. Les codes à utiliser sont tous sur l'endroit , mais voici une introduction rapide: le 1 met en gras le texte, le 31 le rend rouge et le 43 donne un fond jaune. 32 ou 33 serait de différentes couleurs et 44 ou 45 serait différent: vous avez l'idée. Vous pouvez même le faire clignoter (avec un 5) si vous êtes si enclin.

Cela n'utilise aucun module Perl spécial, et Perl est presque omniprésent, donc je m'attendrais à ce qu'il fonctionne à peu près n'importe où. La solution grep est très intelligente, mais le commutateur --color sur grep n'est pas disponible partout. Par exemple, je viens d'essayer cette solution sur une boîte Solaris exécutant bash, et une autre exécutant ksh, et ma machine locale Mac OS X exécutant zsh. Tout fonctionnait très bien. Solaris s'est étouffé avec le grep --color solution, cependant.

De plus, ack est génial, et je le recommande à tous ceux qui ne l'ont pas encore découvert, mais j'ai eu des problèmes pour l'installer sur quelques-uns des nombreux serveurs sur lesquels je travaille. (J'oublie pourquoi: je pense qu'il est lié aux modules Perl.)

Puisque je ne pense pas avoir jamais travaillé sur une boîte Unix qui ne fonctionnait pas ont Perl installé (à l'exception des systèmes de type embarqué, des routeurs Linksys, etc.) Je dirais que c'est à peu près une solution universellement utilisable.

11
iconoclast

Au lieu d'utiliser Grep, vous pouvez utiliser Less:

less file

Rechercher comme ceci: /pattern Enter

Cette volonté:

  1. faites défiler jusqu'à la première ligne correspondante
  2. sortie chaque ligne à partir de là
  3. mettre en surbrillance tous les matchs

Pour passer à la ligne correspondante suivante: n

Pour faire défiler jusqu'à la ligne correspondante précédente: N

Pour basculer la mise en surbrillance: Esc u

Vous pouvez également modifier le couleur de surbrillance si vous le souhaitez.

3
Steven Penny

Tu peux essayer:

Perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

Pas très portable cependant, et même si Perl est installé, vous devrez peut-être télécharger un autre module. De plus, il colorera toute la ligne, pas seulement le mot de recherche.

2
gvkv

Aucune des réponses données jusqu'à présent ne fournit une solution portable .

Voici un portable1 Fonction shell I déjà publiée dans une question fermée en double qui ne nécessite pas d'outils non standard ou d'extensions non standard fournies avec Perl, ack, ggrep, gsed, bash et autres, mais n'a besoin que d'un shell POSIX et des utilitaires obligatoires POSIX sed et printf:

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "$@"
}

Vous pouvez l'utiliser de cette façon:

grepc string_to_search [file ...]

La couleur de surbrillance peut être ajustée en utilisant l'un de ces codes dans l'argument de la commande sed (32m étant vert ici):

30m black
31m red
33m yellow
34m blue
35m Magenta
36m cyan
37m white
7m reverse video

1 Tant que votre terminal prend en charge les séquences d'échappement de couleurs ANSI.

2
jlliagre

ripgrep

Utilisez ripgrep avec son --passthru paramètre:

rg --passthru pattern file.txt

C'est l'un des outils de grepping les plus rapides , car il est construit sur moteur regex de Rust qui utilise des automates finis, SIMD et des optimisations littérales agressives pour rendre la recherche très rapide.

--passthru - Imprime les lignes correspondantes et non correspondantes.

Une autre façon d'obtenir un effet similaire consiste à modifier votre modèle pour qu'il corresponde à la chaîne vide. Par exemple, si vous effectuez une recherche à l'aide de rg foo puis en utilisant rg "^|foo" émettra à la place chaque ligne de chaque fichier recherché, mais seules les occurrences de foo seront mises en évidence. Cet indicateur permet le même comportement sans avoir besoin de modifier le modèle.

2
kenorb

Il existe un moyen beaucoup plus facile de le faire pour GNU grep mais je ne pense pas que ce soit portable (c'est-à-dire, BSD grep):

Dans une pipe:

cat <file> | grep --color=always -z <query>

Sur un fichier:

grep --color=always -z <query> <file>

Le crédit revient à la réponse de Cyrus ici .

1
Erik Nomitch

Une version sed, fonctionne à la fois sur bash et ash.

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "$@"
}
0
yurenchen

OP a demandé grep, et c'est ce que JE RECOMMANDE; mais après avoir essayé de résoudre un problème avec sed, pour mémoire, voici une solution simple avec:

sed $'s/main/\E[31m&\E[0m/g' testt.c

ou

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

Peindra main en rouge.

  • \E[31m: séquence de démarrage de couleur rouge
  • \E[0m: marque de couleur terminée
  • &: le motif correspondant
  • /g: tous les mots d'une ligne, pas seulement le premier
  • $'string' est des chaînes bash avec des caractères d'échappement interprétés

En ce qui concerne grep, cela fonctionne également en utilisant ^ (début de ligne) au lieu de $ (fin de ligne). Exemple:

egrep "^|main" testt.c

Et juste pour montrer cet alias fou qui JE NE RECOMMANDE PAS, vous pouvez même laisser les guillemets ouverts:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

tout le travail! :) Ne vous inquiétez pas si vous oubliez de fermer le devis, bash se souviendra de vous avec un "caractère de ligne continue".

0
Dr Beco