0

I am new to bash, dragged into a problem where I need to update some dynamic parameters in a yaml file

Based on query (search4.subsearch1.name), i need to update

name: old_name

into

name: new_name
  • Here is the sample file:
    search1:
        name: name1
        pass: pass1
        date: date1
    #these are just commented texts
    
    search2:
      #Adding few more commented lines
        myname: somename
        name: name2
        pass: pass2
        someotherparam: param1
    
    search3:
        nameAndSurname: NS
        namingConv: true
        varSet: P3
    
    search4:
        #Again adding some special name: strings here
            myname: somename1
            name: new_name
            pass: new_pass
            ptherparam1: T3
    
        subsearch1:
            #Again adding some special name strings here
                myname: somename2
                name: old_name
                pass: pass2
                ptherparam1: param3
    search5:
        #Again adding some special name strings here
            var1: value1
            name: some_name
            pass: some_pass
    

So based on query (search4.subsearch1.name), I need to update name: old_name into name: new_name

  • Expeced output:
    search4:
        #Again adding some special name: strings here
            myname: somename1
            name: new_name
            pass: new_pass
            ptherparam1: T3
    
        subsearch1:
            #Again adding some special name strings here
                myname: somename2
                name: new_name
                pass: pass2
                ptherparam1: param3
    

Tried with awk and sed but that did not work:

lineNR=$(awk "/\<search4:/{f=1} f && /\<name:/ {print NR; exit}" testfile.txt);sed "${lineNR}s/name.*/name: new_name/" testfile.txt
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
g_jha
  • 19
  • 5
  • how do you define "outside" tool. `awk` and `sed` are "outside" tools too. What about `python` ? – pLumo Feb 10 '21 at 12:10
  • we do not have internet connectivity, and any outside package is not allowed in those linux boxes, but yes it has python – g_jha Feb 10 '21 at 12:14
  • `yq` is a single binary. If you yourself are not allowed to add packages, there will be an administrative process for asking for software to be added to these systems. A "Change Request", maybe. Sometimes it's worth going through the apparent pain of that to deliver more reliable software that in turn is easier to support – roaima Feb 10 '21 at 12:17
  • That's the last hope – g_jha Feb 10 '21 at 12:20
  • Also see [How can I parse a YAML file from a Linux shell script?](https://stackoverflow.com/q/5014632/2344631) over on [SO]. – roaima Feb 10 '21 at 12:25
  • 1
    If you have python, simply install `pyaml` module, a normal user can do that. And you can also install python modules without `pip` if you don't have that. No need to ask the support (although I agree that it might still be worth! ). – pLumo Feb 10 '21 at 12:58
  • You haven't named which system you are using, so it's a complete guess as to what tools might already be installed and what is an "outside tool" – Philip Couling Feb 10 '21 at 17:06

3 Answers3

1

Assuming you can have Mike Farah's yq downloaded and installed, the process becomes trivial

yq eval '.search4.subsearch1.name = "new_name"' file.yml

I note that you say in a comment that "we do not have internet connectivity, and any outside package is not allowed in those linux boxes". Even if you yourself are not allowed to add packages, there will be an administrative process for asking for software to be added to these systems. A "Change Request", maybe. Sometimes it's worth going through the apparent pain of that to deliver more reliable software that in turn is easier to support


For testing, I had to edit the content to ensure that indendation was consistent under search4. I have not edited the content in the question itself

roaima
  • 107,089
  • 14
  • 139
  • 261
  • @romika, could you please share the path of single binary, as i tried this one as well, but it did not update anything – g_jha Feb 13 '21 at 06:40
0

Using any awk in any shell on every Unix box:

$ cat tst.awk
NF && !/^[[:space:]]*#/ && match($0,/^[[:space:]]*/) {
    prevIndent = currIndent
    currIndent = RLENGTH

    name = $1
    sub(/:.*/,"",name)

    if ( currIndent == 0 ) {
        path = name
    }
    else {
        if ( currIndent <= prevIndent ) {
            sub(/\.[^.]+$/,"",path)
        }
        path = path "." name
    }

    if ( path == tgt ) {
        $0 = substr($0,1,currIndent) $1 " " val
    }
}
{ print }

$ awk -v tgt='search4.subsearch1.name' -v val='new_name' -f tst.awk file
search1:
    name: name1
    pass: pass1
    date: date1
#these are just commented texts

search2:
  #Adding few more commented lines
    myname: somename
    name: name2
    pass: pass2
    someotherparam: param1

search3:
    nameAndSurname: NS
    namingConv: true
    varSet: P3

search4:
    #Again adding some special name: strings here
        myname: somename1
        name: new_name
        pass: new_pass
        ptherparam1: T3

    subsearch1:
        #Again adding some special name strings here
            myname: somename2
            name: new_name
            pass: pass2
            ptherparam1: param3
search5:
    #Again adding some special name strings here
        var1: value1
        name: some_name
        pass: some_pass

The above is not a YAML parser and is only intended to work with files structured in the same way as the examples shown and where all indentation is either tabs or blanks but not both.

See https://stackoverflow.com/questions/66173552/update-yaml-value-on-cli#comment116993514_66173552 for another application of the above.

Ed Morton
  • 28,789
  • 5
  • 20
  • 47
  • it worked like charm, but there are few cases where it is failing, please see another sample (ms1.persistentVolume.name)-worked (ms1.ms1Image)-did not work `ms1: persistentVolume: name: orch-logs-pv type: local capacity: 10Gi accessModes: ReadWriteMany nfs: server: 10.10.10.10 path: /var/nfs/general readOnly: true ms1Image: ms1Image ms2Image: ms2Image ms3Image: 1.1.1.1/ms3Image pullPolicy: Never replicaCount: nssmf: 1 nsmf: 1 affinity: key: kubernetes.io/name` – g_jha Feb 13 '21 at 06:29
0

You haven't given us any idea of what system you are using or what's already installed. So this is just an educated guess. A lot of linux distributions ship with "python" and the rise of yaml means that the library "pyaml" it is also often installed. The very fact you are interacting with yaml files yourself makes this more likely.

You can test this really easily. Make a file foo.py containing just:

import yaml
print("I have yaml")

Then on the command line run:

python3 foo.py

If it just prints I have yaml then you have both python and pyaml installed and can use it in a trivial script (update_script.py):

import yaml
import sys

# Load the file into a data structure
with open(sys.argv[1], "r") as file:
    content = yaml.safe_load(file)

# Update the key you want to change
content["search4"]["subsearch1"]["name"] = "new_name"

# Write the data structure back to your file in YAML
with open(sys.argv[1], "w") as file:
    yaml.safe_dump(content, file)

Then just run:

python3 update_script.py config_file.yaml
Philip Couling
  • 17,591
  • 5
  • 42
  • 82