Comment sed uniquement les lignes qui contiennent une chaîne donnée?

13

CONTRIBUTION:

Select ASDF 325 sdfg sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg sdfg 4456 sdrg

PRODUCTION:

Select ASDF 325 XXXX sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg XXXX 4456 sdrg

Donc en bref j'ai besoin de "sed" "sdfg" à "XXXX".

MAIS: uniquement dans les lignes contenant la chaîne "Select ASDF" .. Comment faire? (sed, awk, etc.: \)

LanceBaynes
la source

Réponses:

19

Vous pouvez préfixer la plupart des commandes sed avec une adresse pour limiter les lignes auxquelles elles s'appliquent. Une adresse peut être un numéro de ligne ou une expression régulière délimitée par /.

cat INPUT | sed '/Select ASDF/ s=sdfg=XXXX='

Comme mentionné Peter.O, la commande telle qu'écrite ci-dessus remplacera la première occurrence de any sdfgdans la chaîne contenant Select ASDF. Si vous devez remplacer la correspondance exacte sdfguniquement dans le cas où elle se trouve dans la quatrième colonne, vous devez procéder comme suit:

cat INPUT | sed 's/\(^Select ASDF [^ ]* \)sdfg /\1XXXX /'
se ruer
la source
1
Qu'en est-il d'un autre champ contenant sdfg ? par exemple. 5sdfga
Peter.O
Hmm, en fait ce n'est pas le problème aussi. J'ai mis à jour ma réponse.
rush
y a-t-il des options pour utiliser: sed '/ Sélectionnez ASDF / gs = sdfg = XXXX =' - donc je dois remplacer toutes les occurrences dans une ligne, pas seulement la première. mais sed donne une erreur si j'utilise "g"
LanceBaynes
1
Vous devez taper gaprès dernier =(à la fin de la scommande). Ce sera comme ça:sed '/Select ASDF/ s=sdfg=XXXX=g'
rush
7

Si vous ne modifiez la colonne 4 que si elle a la valeur exacte, il est logique d'utiliser des opérateurs d'égalité au lieu d'expressions régulières.

awk '$1 == "Select" && $2 == "ASDF" && $4 == "sdfg" {$4 = "XXXX"} {print}'
glenn jackman
la source
1
Vite! .. en le comparant, pour 1 million de lignes, avec awk de Birei et sed positionnel de Rush : 0m1.580s vs 0m3.792s vs 0m6.740s
Peter.O
1

En utilisant GNU awk:

awk '
    BEGIN { IGNORECASE = 1 } 
    /^select asdf/ { 
        sub( /\<sdfg\>/, "XXXX", $0 ) 
    } 
    { print }
' infile

Production:

Select ASDF 325 XXXX sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg XXXX 4456 sdrg

MISE À JOUR : éviter IGNORECASEpour un non-GNU awk, et faire correspondre la casse. Merci à jw013 , qui a souligné ce détail:

awk ' 
    /^Select ASDF/ { 
        sub( /\<sdfg\>/, "XXXX", $0 ) 
    } 
    { print }
' infile
Birei
la source
1
Vous devez mentionner IGNORECASEest une extension GNU awk/ gawk.
jw013
1
@ jw013: Merci. Réponse mise à jour avec votre suggestion.
Birei
4
IGNORECASE est erroné dans ce cas, que ce soit GNU ou G'not .. Le critère dans la question est explicitement pour les majusculesASDF
Peter.O