7

I have file with many name: I want to replace only the first one

sed -i "s/\(name:\).*/\1 ${NEW_VALUE}/" ./myFile

Input
-  martin:
    name: Martin D'vloper
    job: Developer
    skills:
      - python
      - perl
      - pascal
-  tabitha:
    name: Tabitha Bitumen
    job: Developer
    skills:
      - lisp
      - fortran
      - erlang

output to change only the first name Martin D'vloper

-  martin:
        name: NEW VALUE!!!
        job: Developer
        skills:
          - python
          - perl
          - pascal
    -  tabitha:
        name: Tabitha Bitumen
        job: Developer
        skills:
          - lisp
          - fortran
          - erlang

It changed all names

I saw something with different syntax

sed '0,/pattern/s/pattern/replacement/' filename

but I can't change sed to this because the dynamic value Could you advise me how to replace only the first one with my syntax ?

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
user1365697
  • 5,819
  • 15
  • 60
  • 96
  • It will make our life easy if you could provide samples of input and expected output, kindly add them in your post and let us know then? – RavinderSingh13 Feb 12 '19 at 12:44
  • Updated with input and output – user1365697 Feb 12 '19 at 12:47
  • I deleted my answer (`sed -z "s/name:[^\n]*/name: $NEW_VALUE/"`) because this question is indeed a duplicate. My answer can now be found [here](https://stackoverflow.com/a/54650952/6770384). – Socowi Feb 12 '19 at 13:17
  • If it's always line 2: `sed -r '2s/(name:).*/\1 NEW VALUE!!!/' file` – Cyrus Feb 12 '19 at 13:22

3 Answers3

5

This should do what you want:

sed -i "0,/name:/{s/name:.*/name: ${NEW_VALUE}/}" ./myFile

It finds the first occurrence of name: and then does the substitution, which is replace 'name: followed by any characters' (.* means any sequence of characters) with 'name: ${NEW_VALUE}' where NEW_VALUE is your dynamical variable from your example.

From man sed

0,addr2

Start out in "matched first address" state, until addr2 is found. This is similar to 1,addr2, except that if addr2 matches the very first line of input the 0,addr2 form will be at the end of its range, whereas the 1,addr2 form will still be at the beginning of its range. This works only when addr2 is a regular expression.

ralz
  • 493
  • 2
  • 8
2

If you are ok with awk then please try following.

awk '/name/ && ++count==1{sub(/name:.*/,"name: NEW VALUE!!!")} 1'  Input_file

In case you have a shell variable and you want to add its value to awk code then try following.

val="new_vaue"
awk -v value="$val" '/name/ && ++count==1{sub(/name:.*/,"name: "value)} 1'  Input_file

In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file to above code.

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • @user1365697, see my 2nd solution where you could substitute values by variable(from shell to awk) and let me know if this helps. – RavinderSingh13 Feb 12 '19 at 12:58
2

This might work for you (GNU sed):

sed -i "/\(name:\).*/{s//\1 ${NEW_VALUE}/;:a;n;ba}" ./myFile

Match on name:, substitute new value and then read and print the remainder of the file.

Or alternative:

sed -z -i 's/\(name:\).*/\1 '"${NEW_VALUE}"'/M' file

N.B. the M flag to the substitution command to restrict the .* within a line.

potong
  • 55,640
  • 6
  • 51
  • 83
  • I have GNU sed version 4.2.1, and it doesn't have the -z option. – Levi Uzodike Mar 01 '21 at 22:02
  • 1
    Explanation of 1st option: when the pattern "name:" followed by any number of characters in the line are found, save "name:" as the first sub-expression(`/\(name:\).*/`), then do these commands(`{`): substitute(`s`) whatever was matched(`//`) for the 1st sub-expression(`\1`) followed by a space and what's saved in the variable NEW_VALUE(`*space*${NEW_VALUE}/`) then(`;`) create label 'a' right here in this command(`:a`) then(`;`) print and go to the next line or exit if there aren't any more(`n`) then(`;`) branch back to label a(`ba`). End of commands for matched pattern(`}`). – Levi Uzodike Mar 01 '21 at 22:25