awk repetition {n} ne fonctionne pas

J'essaie d'imprimer les lignes en utilisant le symbole de répétition {n}, mais cela ne fonctionne pas. Pour. Par exemple, je veux imprimer toutes les lignes dont la longueur est de 4 caractères

awk '/^.{4}$/' test_data 

Le code ci-dessus ne s'imprime pas. Comment le corriger pour que je puisse utiliser le symbole de répétition? Je connais l'alternative comme awk '/^....$/' test_data et awk 'length ==3 ' test_data

Selon le Guide de l'user de GNU Awk: Historique des fonctionnalités , la prise en charge des opérateurs de plage d'expression régulière a été ajoutée dans la version 3.0, mais a initialement nécessité l'option de command line explicite

Nouvelles options de command line:

  • Nouvelles options de command line:
    • L'option –lint-old pour avertir des constructions qui ne sont pas disponibles dans la version Unix d'origine de la version 7 d'awk (voir V7 / SVR3.1).
    • L'option -m de BWK awk. (Brian était encore aux Laboratoires Bell à l'époque.) Ce fut plus tard retiré de son awk et de gawk.
    • L'option –re-interval pour fournir des expressions d'intervalle dans les expressions rationnelles (voir Opérateurs Regexp).
    • L'option –traditional a été ajoutée en tant que meilleur nom pour –compat (voir Options).

Dans gawk 4.0,

Les expressions d'intervalle sont devenues partie intégrante des expressions régulières par défaut

Puisque vous utilisez gawk 3.x, vous devrez utiliser

 awk --re-interval '/^.{4}$/' 

ou

 awk --posix '/^.{4}$/' 

ou (merci @ StéphaneChazelas) si vous voulez une solution portable, utilisez

 POSIXLY_CORRECT=anything awk '/^.{4}$/' 

(puisque --posix ou --re-interval entraînerait une erreur dans d'autres implémentations awk ).

Les ERE ( expressions régulières étendues telles qu'utilisées par awk ou egrep ) n'avaient initialement pas {x,y} . Il a été introduit dans BREs (comme grep ou sed ), mais avec la syntaxe \{x,y\} qui n'a pas brisé la portabilité.

Mais quand il a été ajouté aux ERE avec cette syntaxe {x,y} , il a brisé la portabilité en arrière comme un foo{2} RE correspondait quelque chose de différent avant.

Certaines implémentations ont donc choisi de ne pas le faire. Vous findez que les /bin/nawk /bin/awk , /bin/nawk et /bin/egrep sur Solaris ne l'honorent toujours pas (vous devez utiliser /usr/xpg4/bin/awk ou /usr/xpg4/bin/grep -E ). Idem pour awk et nawk sur FreeBSD (basé sur l' awk maintenu par Brian Kernighan (le k in awk )).

Pour GNU awk , jusqu'à relativement récemment (version 4.0), vous deviez l'appeler avec POSIXLY_CORRECT=anything awk '/^.{4}$/' pour l'honorer. mawk ne l' mawk toujours pas .

Notez que cet opérateur n'est que du sucre syntaxique. .{3,5} peut toujours être écrit ....?.? par exemple (bien que {3,5} soit beaucoup plus lisible, et l'équivalent de (foo.{5,9}bar){123,456} serait bien pire).

Cela fonctionne comme prévu avec GNU awk (gawk):

 $ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/' abcd 

Mais échoue avec mawk qui est plus proche de POSIX awk et, AFAIK, est le défaut sur les systèmes Ubuntu:

 $ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/' $ ## prints nothing 

Donc, une solution simple serait d'utiliser gawk au lieu de awk . La notation {n} ne fait pas partie de la syntaxe POSIX BRE (expression régulière de base). C'est pourquoi grep échoue également ici:

 $ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$' $ 

Cependant, il fait partie de ERE (expressions régulières étendues):

 $ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$' abcd 

Je ne sais pas quelle regex est utilisée par mawk ou POSIX awk , mais je suppose que c'est BRE . Ils utilisent une ancienne version d'ERE selon la réponse de Stéphane . Dans tous les cas, soit vous utilisez apparemment une version de awk qui awk pas ERE, soit votre input n'a pas de lignes avec exactement 4 caractères. Cela peut arriver en raison d'espaces blancs que vous ne voyez pas ou de glyphes unicode, par exemple.