2017-07-05 4 views
2

Supposons un fichier texte multiligne file dans lequel certaines lignes commencent par des espaces.Correspondance de mot clé insensible à la casse dans awk

$ cat file 
foo Baz 
    baz QUX 
    QUx Quux 
BaZ Qux 
BazaaR 

On suppose en outre que je souhaite convertir toutes ces lignes qui commencent par un mot-clé (par exemple « baz ») en lettres minuscules, quel que soit le cas (a) ce mot-clé est écrit en lettres minuscules ou en majuscules (ou toute combinaison de ceux-ci) et (b) ce mot-clé est précédé d'espaces.

$ cat file | sought_command 
foo Baz  # not to lowercase (line does not start with keyword) 
    baz qux  # to lowercase 
    QUx Quux 
baz qux  # to lowercase 
BazaaR   # not to lowercase (line does not start with keyword, but merely with a word containing the keyword) 

Je crois que awk est l'outil pour le faire, mais je ne suis pas certain comment mettre en œuvre l'insensibilité à la casse pour le ciblage des mots clés.

$ cat file | awk '{ if($1 ~ /^ *baz/) print tolower($0); else print $0}' 
foo Baz 
    baz qux 
    QUx Quux 
BaZ Qux  # ERROR HERE: was not replaced, b/c keyword not recognized. 
BazaaR 

EDIT 1: Ajout IGNORECASE=1 semble résoudre le insensibilité à la casse, mais maintenant convertit de façon incorrecte la dernière ligne en minuscules.

$ cat file | awk '{IGNORECASE=1; if($1~/^ *baz/) print tolower($0); else print $0}' 
foo Baz 
    baz qux 
    QUx Quux 
baz qux 
bazaar  # ERROR HERE: should not be converted to lowercase, as keyword not present (emphasis on word!). 
+1

Je ne sais pas si awk supporte la correspondance insensible à la casse (comme le font d'autres dialectes regex). Mais cela devrait fonctionner: '/^* [bB] [aA] [zZ] /'. – Scheff

Répondre

2

Vous connaissez déjà tolower() donc simplement l'utiliser à nouveau dans la comparaison et le test pour un match de chaîne exacte au lieu de regexp partielle:

awk 'tolower($1)=="baz"{$0=tolower($0)}1' 
1

Ajouter un mot-frontière après la chaîne de recherche

$ awk '{IGNORECASE=1; if($1~/^ *baz\>/) print tolower($0); else print $0}' ip.txt 
foo Baz 
    baz qux 
    QUx Quux 
baz qux 
BazaaR 

peut être réécrite comme:

awk 'BEGIN{IGNORECASE=1} /^ *baz\>/{$0=tolower($0)} 1' ip.txt 

Depuis l'ancre de ligne est utilisée, pas besoin de correspondre avec $1. Le 1 à la fin imprimera le dossier, y compris les modifications effectuées

IGNORECASE et \> sont gawk caractéristiques spécifiques. \y peut également être utilisé pour correspondre à la limite de mot


Avec GNU sed

$ sed 's/^[[:blank:]]*baz\b.*/\L&/I' ip.txt 
foo Baz 
    baz qux 
    QUx Quux 
baz qux 
BazaaR 
  • [[:blank:]] correspondent des espaces ou onglet
  • \L& sera minuscule la ligne
  • \b est limite de mot
  • I drapeau pour correspondre insensible à la casse
+0

Je suis impressionné (surtout à propos de 'IGNORECASE'). En ce qui concerne votre échantillon awk: '\>' est la limite du mot? – Scheff

+0

réellement OP mentionné à propos de IGNORECASE dans edit ... et ouais '\>' correspond à la position de fin du mot – Sundeep

+0

Son édition est apparu juste dans la même minute comme votre réponse. Ainsi, je ne savais pas où diriger mon impression. Vous avez gagné à cause du '\>' ... – Scheff