web-dev-qa-db-fra.com

Limiter la sortie de grep aux lignes courtes

J'utilise souvent grep pour trouver des fichiers ayant une certaine entrée comme celle-ci:

grep -R 'MyClassName'

La bonne chose est qu'il renvoie les fichiers, leur contenu et marque la chaîne trouvée en rouge. Le problème, c’est que j’ai aussi d’énormes fichiers dans lesquels tout le texte est écrit en une seule ligne. Maintenant, grep génère trop de résultats lors de la recherche de texte dans ces gros fichiers. Existe-t-il un moyen de limiter la sortie à, par exemple, 5 mots à gauche et à droite? Ou peut-être limiter la sortie à 30 lettres à gauche et à droite?

8
Socrates

grep lui-même n'a que des options pour le contexte basé sur des lignes. Une alternative est suggérée par this post S :

Une solution de contournement consiste à activer l'option "uniquement la correspondance", puis à utiliser le pouvoir de RegExp pour grep un peu plus que votre texte:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

Bien sûr, si vous utilisez la mise en surbrillance des couleurs, vous pouvez toujours à nouveau grep pour colorier uniquement la correspondance réelle:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

Comme autre alternative, je suggérerais fold le texte puis le renvoyer, par exemple:

fold -sw 80 input.txt | grep ...

L'option -s permettra à fold d'insérer des mots sur la ligne suivante au lieu de les séparer.

Ou utilisez un autre moyen de fractionner l'entrée en lignes en fonction de la structure de votre entrée. (La publication SU, par exemple, traitait de JSON. Il était donc préférable d’utiliser jq, etc. pour imprimer de jolies lettres et grep ... ou simplement d’utiliser jq pour effectuer le filtrage en soi ... serait préférable à l’une ou l’autre des solutions indiquées ci-dessus. .)


Cette méthode GNU awk pourrait être plus rapide:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • Dites à awk de scinder les enregistrements sur le modèle qui nous intéresse (-v RS=...) et le nombre de caractères en contexte (-v n=...)
  • Chaque enregistrement après le premier enregistrement (FNR > 1) est un enregistrement où awk a trouvé une correspondance pour le motif.
  • Nous imprimons donc n caractères de fin de la ligne précédente (p) et n caractères de tête de la ligne actuelle (substr($0, 0, n)), ainsi que le texte correspondant de la ligne précédente (qui est prt) .
    • nous définissons p et prt après l’impression , la valeur que nous définissons est utilisée par la ligne suivante
    • RT est un GNUism, c'est pourquoi c'est GNU awk.

Pour une recherche récursive, peut-être:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +
15
muru

Utiliser only-matching en combinaison avec d'autres options (voir ci-dessous) peut être très proche de ce que vous recherchez, sans la charge de traitement de l'expression régulière mentionnée dans l'autre réponse.

grep -RnHo 'MyClassName'
  • n sortie numérique, affiche le numéro de ligne de la correspondance
  • H nom_fichier, affiche le nom du fichier au début de la ligne du match
  • o seulement correspond, affiche uniquement la chaîne de caractères mathématique, pas la ligne entière
1
Robert Riedl