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
- Official documentation
- Handle Dates
- Navigate structured Yaml files
- Advanced usage
- Introduction to Yaml
Other tools
- A bash script to add front matter to a bunch of Markdown files
- https://github.com/tomwright/dasel
- https://github.com/pandastrike/yaml-cli
- Written in Python:
- NPM based editors
- https://chrisdmacrae.github.io/front-matter-manipulator (unmaintained)
- https://github.com/hilja/file-batcher (unmaintained)
- https://github.com/dworthen/js-yaml-front-matter (unmaintained)
- Jinja: https://karlredman.github.io/EditFrontMatter/
- A collection: Frontmatter Tools