/errors/sed/unknown-option-to-s
sed: -e expression #1, char N: unknown option to `s'
- tool
- sed
- exit code
- 1
- versions
- GNU sed 4.x
- os
- linux, macos, windows
unknown option to `s' means sed finished reading s/pattern/replacement/ earlier than you intended and found unexpected characters where the flags (g, i, p, a number) belong. The cause is nearly always a / inside the pattern or the replacement, such as a file path. Use a different delimiter: sed 's|/usr/local/bin|/opt/bin|'. Any character after s becomes the delimiter.
Reproduce it
echo 'path=/usr/local/bin' > app.conf
sed 's/path=/usr/local/bin/path=/opt/bin/' app.conf
echo "exit status: $?"Output
sed: -e expression #1, char 13: unknown option to `s' exit status: 1
sed reads s/path=/usr/ as the complete command and then sees local/... where flags belong. The character number in the message points at the first character it could not use as a flag (here the l of local).
Fix: another delimiter
echo 'path=/usr/local/bin' > app.conf
sed 's|/usr/local/bin|/opt/bin|' app.conf
sed 's#/usr/local#/opt#' app.conf
sed 's/\/usr\/local/\/opt/' app.confOutput
path=/opt/bin path=/opt/bin path=/opt/bin
All three are equivalent. | and # are common choices; pick one that does not appear in the data.
Variables in the replacement
echo 'root=/var/www' > site.conf
NEW_ROOT=/srv/site
sed "s/root=.*/root=$NEW_ROOT/" site.conf
echo "exit status: $?"
sed "s|root=.*|root=$NEW_ROOT|" site.confOutput
sed: -e expression #1, char 17: unknown option to `s' exit status: 1 root=/srv/site
The shell expands $NEW_ROOT before sed sees the expression, so the slashes in its value break the command. Use a delimiter that cannot appear in the value. If the value can contain anything, escape it first: printf '%s' "$NEW_ROOT" | sed 's/[|&\\]/\\&/g' escapes the | delimiter, & and backslashes for use in the replacement.
Flags sed accepts after the third delimiter
Everything after the closing delimiter must be a flag (or ;, a newline or } ending the command). GNU sed accepts these:
| Flag | Meaning |
|---|---|
| g | Replace every match on the line, not only the first |
| N (a number) | Replace only the Nth match; combined with g, the Nth and all later ones |
| p | Print the pattern space if a substitution was made (useful with -n) |
| w FILE | Write the line to FILE if a substitution was made; must be the last flag |
| i or I | Match case-insensitively (GNU extension) |
| m or M | Multi-line mode for ^ and $ (GNU extension) |
| e | Run the pattern space as a shell command and replace it with the output (GNU extension) |
Any other letter there produces the error, which is what happens when a path leaks into the flag position: in s/path=/usr/local/... the would-be flag is l. POSIX only defines g, a number, p and w; the other flags are extensions, so check the target sed before relying on them in portable scripts.
Other ways to trigger it
echo 'a' | sed 's/a/b/x'
echo 'a' | sed 's/a/b/ s/b/c/'
echo 'a' | sed 's/a/b/; s/b/c/'
echo 'a' | sed -e 's/a/b/' -e 's/b/c/'Output
sed: -e expression #1, char 7: unknown option to `s' sed: -e expression #1, char 8: unknown option to `s' c c
The first command has a typo in the flags. The second joins two commands with a space, so sed reads s of the second command as a flag. A ; or a second -e separates them correctly.
How to confirm the fix
Run the corrected expression without -i first and compare its output with the input; once it prints what you expect, add -i (on BSD and macOS, -i ''). An exit status of 0 and the changed line in the output mean the command parsed correctly.
Prevention
In scripts, choose the delimiter from the data, not from habit: paths and URLs almost always contain /, while | rarely appears. When the replacement comes from user input or a variable, escape it before building the expression, or use a tool that takes the replacement as data instead of code, such as awk -v new="$NEW_ROOT" or a short Python script.
FAQ
Which characters can I use as the s delimiter?
Any single character except a backslash or a newline. Pick one that cannot appear in the pattern or the replacement; | , # and : are common choices for paths.
What does char N in the message mean?
It is the position in the sed expression, counted from 1, where sed stopped parsing. For this error it points at the first character after the third delimiter that is not a valid flag.
Does the -i option cause this error?
No. -i edits the file in place but does not change how the s command is parsed; the same expression fails with or without -i.