Question: I have the following text file: **file.text**

```
Cygwin
value: c
Unix-keep
value: u
Linux
value: l
Unix-16
value: u
Solaris
value: s
Unix-replace-1
value: u
Unix-replace-2
value: u

```

I want to replace all lines values based on previous string : starting with **Unix-** but excluding containing string **keep**

So in the end affected lines sould be the ones after:
Unix-replace-1 and Unix-replace-2 with value **value: NEW\_VERSION**

Expected output:

```
Cygwin
value: c
Unix-keep
value: u
Linux
value: l
Unix-16
value: NEW_VERSION
Solaris
value: s
Unix-replace-1
value: NEW_VERSION
Unix-replace-2
value: NEW_VERSION

```

I tried following sed script:

```
sed '/^Unix-/ {n;s/.*/value: NEW_VERSION/}' file.text

```

but this can only get starting but not excluding -keep substrings. I am not sure how to combine the excluded ones.

Any ideas?

Answer: 
```
$ awk -v new='NEW_VERSION' 'f{$0=$1 FS new} {f=(/^Unix-/ && !/keep/)} 1' file
Cygwin
value: c
Unix-keep
value: u
Linux
value: l
Unix-16
value: NEW_VERSION
Solaris
value: s
Unix-replace-1
value: NEW_VERSION
Unix-replace-2
value: NEW_VERSION

```
Using a proper [xml](/questions/tagged/xml "show questions tagged 'xml'") parser (**the question was originally plain XML before edited by OP**):

The XML edited to be valid (closing tags missing) :

```
<project>
    <Cygwin>
        <version>c</version>
    </Cygwin>
    <Unix-keep>
        <version>u</version>
    </Unix-keep>
    <Linux>
        <version>l</version>
    </Linux>
    <Solaris>
        <version>s</version>
    </Solaris>
    <Unix-replace-1>
        <version>u</version>
    </Unix-replace-1>
    <AIX>
        <version>a</version>
    </AIX>
    <Unix-replace-2>
        <version>u</version>
    </Unix-replace-2>
</project>

```

The command:

```
xmlstarlet ed -u '//project/*
    [starts-with(name(), "Unix") and not(starts-with(name(), "Unix-keep"))]
    /version
' -v 'NEW_VERSION' file

```

To edit the file *in place*, use 

```
xmlstarlet ed -L -u ...

```