Wie setze ich nur die Zeilen, die einen bestimmten String enthalten?

13

EINGANG:

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

AUSGABE:

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

Kurz gesagt, ich muss "sdfg" auf "XXXX" setzen.

ABER: nur in Zeilen, die den String "Select ASDF" enthalten. Wie kann ich das machen? (sed, awk, etc.: \)

LanceBaynes
quelle

Antworten:

19

Sie können den meisten sed-Befehlen eine Adresse voranstellen , um die Zeilen einzuschränken, für die sie gelten. Eine Adresse kann eine Zeilennummer oder ein durch begrenzter regulärer Ausdruck sein /.

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

Wie bereits erwähnt, ersetzt der oben beschriebene Befehl das erste Vorkommen von "any" sdfgin der Zeichenfolge, die enthält Select ASDF. Wenn Sie die exakte Übereinstimmung sdfgnur dann ersetzen müssen, wenn sie sich in der vierten Spalte befindet, sollten Sie folgendermaßen vorgehen:

cat INPUT | sed 's/\(^Select ASDF [^ ]* \)sdfg /\1XXXX /'
eilen
quelle
1
Was ist mit einem anderen Feld, das sdfg enthält ? z.B. 5sdfga
Peter.O
Hmm, eigentlich ist das auch nicht das Problem. Ich habe meine Antwort aktualisiert.
Ansturm
Gibt es irgendwelche Optionen für die Verwendung von: sed '/ Select ASDF / gs = sdfg = XXXX =' - also muss ich alle Vorkommen in einer Zeile ersetzen, nicht nur das erste. aber sed gibt
fehler
1
Sie müssen gnach dem letzten =(am Ende des sBefehls) eingeben. Es wird so sein:sed '/Select ASDF/ s=sdfg=XXXX=g'
Ansturm
7

Wenn Sie Spalte 4 nur ändern, wenn sie den genauen Wert hat, ist die Verwendung von Gleichheitsoperatoren anstelle von regulären Ausdrücken sinnvoll.

awk '$1 == "Select" && $2 == "ASDF" && $4 == "sdfg" {$4 = "XXXX"} {print}'
Glenn Jackman
quelle
1
Schnell! .. Vergleichen Sie es für 1 Million Zeilen, mit Birei awk und Rush Position sed: 0m1.580s vs 0m3.792s vs 0m6.740s
Peter.O
1

Verwenden von GNU awk:

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

Ausgabe:

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

UPDATE : Vermeiden Sie IGNORECASEfür ein nicht-GNU awkund Match case-sensitive. Vielen Dank an jw013 , der auf dieses Detail hingewiesen hat:

awk ' 
    /^Select ASDF/ { 
        sub( /\<sdfg\>/, "XXXX", $0 ) 
    } 
    { print }
' infile
Birei
quelle
1
Sie sollten erwähnen, IGNORECASEist eine GNU awk/ gawkErweiterung.
JW013
1
@ jw013: Danke. Aktualisierte Antwort mit Ihrem Vorschlag.
Birei
4
IGNORECASE ist in diesem Fall falsch, egal ob es GNU oder G'not ist. Das Kriterium in der Frage ist explizit für GroßbuchstabenASDF
Peter.O