sed Quoting Pitfalls in YAML CI Files
A sed command inside a CI run step passes through YAML and shell parsing before sed sees it, and each layer can mangle quotes.
Most sed CI failures are not sed bugs, they are quoting. The command travels through YAML, then the shell, then sed, and every layer has its own rules.
What it does
In a workflow run step, YAML reads the block, the shell parses the resulting string, and only then does sed receive its program. Single quotes around the sed program stop the shell from expanding $ and the slash, but a single quote inside the program ends the quoting early.
Common usage
# safe: single-quoted program, no shell expansion
- run: sed -i 's/old/new/' config.yml
# need a shell variable? use double quotes and escape
- run: sed -i "s/version=.*/version=$NEW_VER/" app.ini
# a literal single quote in the program: end-quote, escaped quote, re-quote
- run: sed -i 's/it'\''s/it is/' fileOptions
| Layer | Pitfall |
|---|---|
| YAML | A program with : may need the whole run block quoted |
| Shell single quotes | No $ expansion, but no embedded single quote either |
| Shell double quotes | Allows $VAR but the shell now eats $, \, and backticks |
| Embedded ' | Close, write '\'', then reopen the quote |
| Backslashes | Double quotes may consume a \ before sed sees it |
In CI
Default to single quotes around the sed program so the shell leaves it alone, and only switch to double quotes when you must interpolate a workflow variable. For multi-line YAML blocks, the | or > scalar styles change how newlines and quotes are read, so keep complex sed on one line.
Common errors in CI
An unbalanced quote yields the shell error sed: -e expression #1, char N: unterminated `s' command because the shell merged the program with the next token. Using double quotes around a replacement that contains $ or \1 lets the shell expand or strip it before sed runs, so the backreference vanishes.