'How to split a YAML into multiple files with a proper name

I have a valid YAML:

---
name: first
metadata: a
---
name: second
metadata: b
---
name: third
metadata: c

How can I split it using a one-liner AWK script in files first.yaml, second.yaml and third.yaml? Solution needs to work with any name.

Just splitting the file works but I can't figure out how to add proper file names instead of line numbers (NR):

awk '/\-\-\-/{f=NR".yaml"}; {print >f}'


Solution 1:[1]

EDIT: Adding 1 more solution.

awk '
/name:/{
  close(file)
  file=$NF".yaml"
}
file!="" && !/^--/{
  print > (file)
}
' Input_file


Could you please try following.

awk '
prev!=file{
  close(prev)
}
/name:/{
  file=$NF".yaml"
}
file!="" && !/^--/{
  print > (file)
  prev=file
}
' Input_file

Sample output file will be:

cat first.yaml
name: first
metadata: a

Explanation: Adding detailed explanation for above code.

awk '                     ##Starting awk program from here.
prev!=file{               ##Checking condition if prev is NOT equal to file variable then do following.
  close(prev)             ##Closing output file, to avoid too many files opened in back-end by mentioning close(prev) command here.
}                         ##Closing condition prev!=file here.
/name:/{                  ##Checking condition if line has string name: in it then do following.
  file=$NF".yaml"         ##Creating variable named file whose value is $NF(last field of current line) .yaml
}                         ##Closing name: condition here.
file!="" && !/^--/{       ##Checking condition if variable file is NOT NULL AND line is NOT starting with dash then do following.
  print > (file)          ##Printing current line into output file whose name is there in file variable.
  prev=file               ##Setting prev variable whose value is variable file here.
}                         ##Closing BLOCK for file!="" && !/^--/ condition here.
'  Input_file             ##Mentioning Input_file name here.

Solution 2:[2]

awk '/^name:/{close(out); out=$2 ".yaml"} !/^-+$/{print > out}' file

Solution 3:[3]

Here's another:

$ awk -v RS="---\n" 'NR>1{f=$2 ".yaml";printf "%s",$0 > f;close(f)}' file

Results:

$ cat first.yaml
name: first
metadata: a

It worked with GNU awk, mawk and busybox awk but produced a leeding empty line on awk version 20121220.

Solution 4:[4]

You can do it simply using the package yq :

yq -s '.name' file.yml 

Solution 5:[5]

Here is another way:

This is to address if name: is in the middle like many kubernetes yaml files.

awk '/^..name:/{file=$2 ".yaml"} !/^-/{temp=temp $0 "\n"} /^-/{print temp>file; close(file); temp=""}' inputFile

Please note, this expects the

name: to start after two spaces.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ed Morton
Solution 3
Solution 4 PL Sergent
Solution 5