Replace value of a line in a yml with bash

web:
  image: nginx
  volumes:
    - "./app:/src/app"
  ports:
    - "3030:3000"
    - "35729:35729"

I would like to have a bash script to replace the nginx for an argument with bash script.

./script apache

Will replace nginx for apache

You can use this: sed -r 's/^(\s*)(image\s*:\s*nginx\s*$)/\1image: apache/' file

Sample run:

$ cat file
web:
  image: nginx
  volumes:
    - "./app:/src/app"
  ports:
    - "3030:3000"
    - "35729:35729"
$ sed -r 's/^(\s*)(image\s*:\s*nginx\s*$)/\1image: apache/' file
web:
  image: apache
  volumes:
    - "./app:/src/app"
  ports:
    - "3030:3000"
    - "35729:35729"

To persist the changes into the file you can use in-place option like this:

$ sed -ri 's/^(\s*)(image\s*:\s*nginx\s*$)/\1image: apache/' file

If you want it inside a script you can just put the sed command inside a script and execute it with $1 in sustitution.

$ vim script.sh 
$ cat script.sh 
sed -ri 's/^(\s*)(image\s*:\s*nginx\s*$)/\1image: '"$1"'/' file
$ chmod 755 script.sh 
$ cat file 
web:
  image: nginx
  volumes:
    - "./app:/src/app"
  ports:
    - "3030:3000"
    - "35729:35729"
$ ./script.sh apache
$ cat file 
web:
  image: apache
  volumes:
    - "./app:/src/app"
  ports:
    - "3030:3000"
    - "35729:35729"
$

source /dev/stdin <<<"$(echo 'cat <<EOF >final.yml'; cat template.yml; echo EOF;)" There is a way to do PEM files without resorting to AWK, but again it seems less readable and has one issue. If your last line in the PEM file does not have a newline, the read loop below will drop the last line.

script:

#!/bin/bash
sed -i.bak "s/\bnginx\b/$1/g" file
# \b matches for word boundary
# -i changes the file in-place
# -i.bak produces a backup with .bak extension

Now you can do ./script apache to replace nginx with apache.

To update file pass the -i option: sed -i 's/foo/bar/g' hello.txt cat hello.txt The g/ means global replace i.e. find all occurrences of foo and replace with bar using sed. If you removed the /g only first occurrence is changed:

You could create your script.sh as follows:

#!/bin/bash
# $1 image value you want to replace
# $2 is the file you want to edit
sed -i "" "/^\([[:space:]]*image: \).*/s//\1$1/" $2

And then run: ./script.sh apache filename.yaml

Read YAML file from Bash script. GitHub Gist: instantly share code, notes, and snippets.

since this is apparently a docker-compose file, you might want to try

 image: ${webserver_image}

and then set:

 webserver_image=[nginx | apache]

before launching. i believe this should give you a nice interpolation.

I'm trying to make an awk script to compare values I've set as var1, var2, and var3 earlier in the script to the values in the userinputted column of four text files called Node1.txt, Node2.txt, Node3.txt, and Node4.txt and then replace the values in that userinputted column with either ttt or gcc,

I want to replace always second value in second row. My real input data has thousands of rows and about 20 columns with different numbers. In every file I want to replace value in specific field (for example second row, second column).

$ ansible-playbook -i hosts my.yml. References: replace – Replace all instances of a particular string in a file using a back-referenced regular expression. lineinfile – Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression.

Macro syntax variables remain unchanged with no value because an empty value like $() might mean something to the task you are running and the agent should not assume you want that value replaced. For example, if you use $(foo) to reference variable foo in a Bash task, replacing all $() expressions in the input to the task could break your Bash

Comments
  • As it seems you want to override value in a docker-compose file, you might want to look at my docker compose wrapper program that allows default that can be overridden by environment variables (e..g to make the difference between a testing and production system). Because it supports YAML 1.2, it also relieves you of the need to quote those "3030:3000" port mappings that could be interpreted by compose's default YAML 1.1 parser as sexagesimals
  • Does empty quotes "" are necessary? What they do?
  • Correct answer: sed -i "/^\([[:space:]]*image: \).*/s//\1$1/" $2 , Remove the empty quotes otherwise it will complain about the no file or directory error !
  • to make it work both in Linux and OSX, add .bak next to -i e.g. sed if.bak .... Then of course you can delete .bak file.