Comment exclure certains files ne correspondant pas à certaines extensions avec grep?

Je veux sortir toutes les lignes contenant le mot OK récursivement à partir d'un directory. Mais il y a quelques extensions que je dois exclure du résultat:

 *~ *.map *.js except *.debug.js 

J'ai essayé:

 grep -r --exclude={*~,*.map} "OK" /some/dir 

Sauf que je ne sais pas comment supprimer du résultat tous ces files .js non-debug. Toute aide est très appréciée.

Je voudrais juste passer cela à travers un deuxième grep pour les supprimer:

 grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js' 

Le -v inverse la correspondance, imprimant des lignes qui ne correspondent pas au motif et le -P active les expressions régulières compatibles avec Perl, ce qui nous permet d'utiliser des lookbehinds négatifs . Cette regex particulière correspondra à .js qui n'est pas précisée par debug ce qui signifie (puisque nous inversons les correspondances) que seuls les files .js seront imprimés.

Cependant, comme @QuestionOverflow l'a souligné dans les commentaires, cela pourrait avoir l'effet secondaire involontaire de filterr les lignes qui contiennent OK et js puisque le grep -v est appliqué à toute la sortie, pas seulement le nom du file. Pour éviter cela, il suffit d'append un deux-points (c'est ce que grep utilise pour séparer les noms de files du contenu du file):

 grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:' 

Cela échouera toujours si votre ligne d'input contient foo.js: ou si votre nom de file contient foo.js: Donc, pour être sûr, utiliser une approche différente:

 grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t' 

Le -T provoque grep à imprimer un onglet entre le nom du file et le contenu du file. Donc, si nous ajoutons simplement un \t à la fin de l'expression rationnelle, il ne fera que correspondre aux noms de files, et non au contenu de la ligne.

Pourtant, l' utilisation de find peut avoir plus de sens indépendamment.

Je voudrais utiliser find pour localiser les files et canaliser le résultat via xargs :

 $ find . -type f \! -name "*~" \ \! -name "*.map" \ \! \( -name "*.js" -and \! -name "*.debug.js" \) \ -print0 | xargs -0 grep "OK" 

Cela search tous les files ne correspondant pas " *~ ", " *.map " ou " *.js mais pas *.debug.js ".

En utilisant find vous pouvez facilement searchr des règles assez complexes et cette approche vous évite de supprimer accidentellement des faux positifs, ce qui pourrait arriver avec grep double.

Avec zsh vous pouvez faire:

 setopt extendedglob grep OK some/dir/**/^(*~|*.map|(^*debug).js) 

Bien entendu, la list d'arguments n'est pas trop longue, auquel cas vous pouvez toujours faire:

 printf '%s\0' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK 

Si cela ne vous dérange pas de voir la sortie légèrement en panne (si vous le faites, vous pouvez le sortinger):

 grep -r --exclude={*~,*.map,*.js} "OK" /some/dir **/*.debug.js 

Cela nécessite que votre shell shopt -s globstar charge ** pour les globes récursifs: zsh sort de la boîte, bash fait après avoir exécuté shopt -s globstar , ksh93 fait après avoir exécuté set -o globstar .

Sans support ** dans le shell, vous pouvez utiliser deux commands grep:

 grep -r --exclude={*~,*.map,*.js} "OK" /some/dir grep -r --include=*.debug.js "OK" /some/dir