Content files in Hugo are written in Markdown, and look like this:

---
title: hello
tags: fruits
---

Here is an article about **fruits**

When you switch to a new theme or migrate content, you need to edit the Front Matter of multiple files.

We can make use of Yq, a standalone executable providing batch Front Matter edition from the terminal.
YAML, JSON and XML are supported, and binaries are available for Linux, Mac, FreeBSD and Windows.

As an example, here is how to bulk edit tags: from every Markdown files:

find -name  "*.md" -exec yq '.tags = "food"' -i {} \;

Basic examples are missing in the offical documentation, so here is a memo.

First, let’s read the files

Here is how to extract the title: variable from example.md

yq '.title' example.md

Get title: from multiple files:

yq '.title' fruits.md example.md

(Hint: Separator --- can be removed with --no-doc)

Get every .md files and show title

find -name  "*.md" -exec yq '.title'  {} \;

Now let’s update our files

Starting gently with a single file

Let’s imagine that we want to modify the tags variable.

Run a test

yq '.tags = "food"' example.md

Write the file with -i

yq '.tags = "food"' example.md -i

Note: special characters must be escaped:

yq '.title = "This is a \"special\" update"' example.md -i

See the documentation for advanced guidance on special characters.

Batch modifications

Preview the modifications with a test run:

find -name  "*.md" -exec yq '.tags = "food"' {} \;

Add -i to apply

find -name  "*.md" -exec yq '.tags = "food"' -i {} \;

Solving the error “bad file mapping values are not allowed”

You may get messages like “Error: bad file .. mapping values are not allowed in this context

In such situation, use --front-matter="process" like this:

find -name  "*.md" -exec yq --front-matter="process" '.tags = "food"' -i {} \;

Note: this will also fix/change the indentation of your Front Matter.

Other nice features

yq also provides the following features:

Convert YAML file to JSON

yq config.yml -o json

Convert YAML file to XML

yq config.yml -o xml

Create a new file with custom content

yq -n '.title="A new post"' > new.yml

Note: Front matter separator --- are not added to new files.

Combine multiple Yaml files into one

yq '.' folder/*.yml

Use conditionals with if / else

See this hidden corner of the doc

The complete man page

$ yq --help

yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/) 
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.

Usage:
  yq [flags]
  yq [command]

Examples:

# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.

# read the "stuff" node from "myfile.yml"
yq '.stuff' < myfile.yml

# update myfile.yml in place
yq -i '.stuff = "foo"' myfile.yml

# print contents of sample.json as idiomatic YAML
yq -P sample.json


Available Commands:
  completion       Generate the autocompletion script for the specified shell
  eval             (default) Apply the expression to each document in each yaml file in sequence
  eval-all         Loads _all_ yaml documents of _all_ yaml files and runs expression once
  help             Help about any command
  shell-completion Generate completion script

Flags:
  -C, --colors                        force print with colors
  -e, --exit-status                   set exit status if there are no matches or null or false is returned
      --expression string             forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.
      --from-file string              Load expression from specified file.
  -f, --front-matter string           (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
      --header-preprocess             Slurp any header comments and separators before processing expression. (default true)
  -h, --help                          help for yq
  -I, --indent int                    sets indent level for output (default 2)
  -i, --inplace                       update the file inplace of first file given.
  -p, --input-format string           [yaml|y|props|p|xml|x] parse format for input. Note that json is a subset of yaml. (default "yaml")
  -M, --no-colors                     force print with no colors
  -N, --no-doc                        Don't print document separators (---)
  -n, --null-input                    Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.
  -o, --output-format string          [yaml|y|json|j|props|p|xml|x] output format type. (default "yaml")
  -P, --prettyPrint                   pretty print, shorthand for '... style = ""'
  -s, --split-exp string              print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.
      --split-exp-file string         Use a file to specify the split-exp expression.
  -r, --unwrapScalar                  unwrap scalar, print the value with no quotes, colors or comments (default true)
  -v, --verbose                       verbose mode
  -V, --version                       Print version information and quit
      --xml-attribute-prefix string   prefix for xml attributes (default "+")
      --xml-content-name string       name for xml content (if no attribute name is present). (default "+content")
      --xml-keep-namespace            enables keeping namespace after parsing attributes (default true)
      --xml-raw-token                 enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details. (default true)
      --xml-strict-mode               enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.

Use "yq [command] --help" for more information about a command.

Further reading

Other tools