The config file that needs a one-line change, the setting that must be updated across twenty servers, and the edit that sed performs in one command is the operation that a text editor would need twenty logins for. Sed is the stream editor that every Unix system ships, and the -i flag with the backup suffix is the safety pattern that makes the in-place editing reversible. This article covers the sed vocabulary that the config editing needs: the substitution command, the address patterns that target specific lines, the in-place editing with backup, and the scenarios where sed is the right tool and where it is not.
The substitution command and the basic syntax
The sed substitution is the s command, and the syntax is s/old/new/flags. The basic substitution:
sed 's/old_value/new_value/' /etc/app/config.conf
which prints the modified content to stdout without changing the file, and the stdout preview is the test that confirms the substitution before the in-place edit. The -i flag performs the edit in place:
sed -i 's/old_value/new_value/' /etc/app/config.conf
which modifies the file directly, and the -i.bak variant creates a backup before editing:
sed -i.bak 's/old_value/new_value/' /etc/app/config.conf
which writes the original to config.conf.bak and the modified version to config.conf, the backup that makes the in-place edit reversible. The .bak suffix is the convention, and the convention means that the backup files accumulate and need cleanup, find /etc -name '*.bak' -mtime +7 -delete.
The address patterns that target specific lines
The substitution without an address applies to every line, and the address narrows the substitution to the lines that match. The line number address:
sed '10s/old/new/' config.conf
The pattern address:
sed '/^listen /s/80/8080/' nginx.conf
which substitutes only on lines that start with listen, the targeting that prevents unintended substitutions on other lines. The range address:
sed '/^server {/,/^}/s/port 80/port 8080/' nginx.conf
which substitutes only within the server block, the range that the comma between the two patterns defines.
The flags that control the substitution behavior
The g flag substitutes every occurrence on the line, not just the first, and the missing g is the classic mistake that replaces only the first occurrence. The i flag makes the pattern case-insensitive. The c flag in GNU sed confirms each substitution. The combination:
sed -i 's/SELINUX=enforcing/SELINUX=permissive/gi' /etc/selinux/config
which substitutes case-insensitively on every occurrence.
The multi-command and the script file
The -e flag chains multiple substitutions in one invocation:
sed -i -e 's/old1/new1/g' -e 's/old2/new2/g' config.conf
and the -f flag reads the sed commands from a file, the script file that the complex editing uses:
sed -i -f /etc/app/transform.sed config.conf
The transform file contains one sed command per line, and the file is the versioned transformation that the deployment applies.
The scenarios where sed is and is not the right tool
Sed is the right tool for the line-based substitution, the one-line change in a config file, the value update across multiple files, the pattern replacement that a text editor would do manually. Sed is not the right tool for the structured data editing, the JSON and YAML files where the indentation matters and where a dedicated tool like jq or yq is the correct choice. Sed is not the right tool for the binary files, the compilation artifacts and the images that the text tools corrupt.
The checklist for the sed config editing
The checklist for the sed config editing is short. Preview with the stdout form before using -i. Use -i.bak for the reversible in-place edit. Use the address pattern to target the specific lines. Use the g flag for global substitution. Verify the result after the edit. And clean up the .bak files after the verification, the cleanup that prevents the .bak accumulation from becoming its own storage problem.
The multi-line editing and the hold space
Sed's hold space is the secondary buffer that holds text between pattern space iterations, and the hold space is the mechanism for multi-line operations: the append, the prepend and the swap between lines. The N command reads the next line into the pattern space, the two-line processing that pairs consecutive lines:
sed 'N; s/\n/ /' config.conf
which joins every pair of lines into one, the operation that the line-based tool needs for the multi-line patterns. The hold space commands: h copies the pattern space to the hold space, H appends, g copies the hold space to the pattern space, G appends, and x swaps the two spaces. The hold space is the memory that sed carries between lines, and the memory is what enables the multi-line transformations that the single-line substitutions cannot do.
The find and sed combination for bulk edits
The find and sed combination applies the substitution across multiple files, and the find command locates the files and executes sed on each:
find /etc/app -name '*.conf' -exec sed -i.bak 's/old_server/new_server/g' {} +
which finds every .conf file under /etc/app, creates a .bak for each, and substitutes old_server with new_server in all of them. The find + exec pattern is the bulk edit that the fleet migration uses, and the + at the end batches the files into as few sed invocations as possible.
The xargs alternative:
find /etc/app -name '*.conf' | xargs sed -i.bak 's/old/new/g'
performs the same operation with the xargs pipeline, and the choice between -exec and xargs is a performance consideration rather than a functional one: both work, and the one that the team uses consistently is the one that matters.
The sed in the deployment pipeline
The deployment pipeline that uses sed for the config transformation is the pipeline that the CI/CD system runs, and the sed commands in the pipeline are the template rendering that the config management would otherwise do. The Dockerfile that uses sed to configure the application:
RUN sed -i 's/listen 80/listen 8080/' /etc/nginx/nginx.conf
RUN sed -i 's/debug/info/' /etc/app/config.yaml
and the sed commands in the Dockerfile are the build-time configuration that the image carries. The sed that the entrypoint script uses is the runtime configuration that the environment variables drive:
sed -i "s/DATABASE_HOST/$DB_HOST/" /etc/app/config.conf
and the environment variable substitution at runtime is the twelve-factor app pattern that the containerized application uses.
The regex features that sed supports
Sed uses basic regular expressions by default, and the -E flag enables extended regular expressions, the syntax that grep -E uses and that the modern regex tools use. The extended regex syntax:
sed -E 's/(\d{4})-(\d{2})-(\d{2})/\3-\2-\1/' dates.txt
which rearranges the date from YYYY-MM-DD to DD-MM-YYYY, the capture groups with the parenthesized patterns and the backreferences with the \1 \2 \3 notation. The extended regex makes the patterns readable, and the -E flag is the recommended flag for any regex more complex than a simple string match.
The character classes in sed follow the POSIX convention: [[:digit:]] for digits, [[:alpha:]] for letters, [[:space:]] for whitespace, and the POSIX classes are the portable alternative to the \d and \w shortcuts that GNU sed supports but POSIX sed does not.
The delete, append and insert commands
The d command deletes lines, the a command appends after, the i command inserts before, and the c command changes the line. The deletion of comment lines:
sed '/^#/d' config.conf
The append after the matching line:
sed '/^\[server\]/a\listen_port = 8080' config.conf
The insert before the matching line:
sed '/^\[server\]/i\# Server configuration' config.conf
The change command replaces the entire line:
sed '/^timeout/c\timeout = 60' config.conf
These commands are the editing vocabulary that the config file manipulation needs, and the vocabulary is complete enough that sed is the only tool the config editing requires.
The GNU sed extensions and the portability considerations
GNU sed has extensions that the POSIX sed does not: the -i with a suffix, the \d and \w shortcuts in regex, and the in-place editing itself. The portable sed script works on every Unix system, and the GNU extensions make the script GNU-only. The portability consideration matters for the scripts that run on multiple platforms, the Alpine containers and the macOS workstations, and the portable sed script avoids the GNU extensions or checks for them at runtime.
The -i flag without a suffix is a GNU extension, and the portable in-place editing creates a temp file and moves it, the two-step pattern that works everywhere. The -i.bak with the suffix works on GNU sed and on the BSD sed with a space: -i '.bak', and the space between -i and the suffix is the BSD convention that GNU sed tolerates.
The safety patterns and the disaster prevention
The sed that edits the production config file is the sed that can break the production server, and the safety patterns prevent the breakage. The stdout preview before the in-place edit is the first pattern, the test that shows what the substitution will do. The -i.bak backup is the second pattern, the rollback that the broken config needs. The config file validation after the edit is the third pattern, the syntax check that the application provides:
sed -i.bak 's/old/new/' /etc/nginx/nginx.conf && nginx -t
The nginx -t test validates the config file, and the test that fails means the sed broke the config, the rollback is the .bak restoration, and the test-and-rollback pair is the safety pattern that makes the sed editing safe.
The version control that the /etc directory uses, the etckeeper tool from the earlier articles, is the ultimate safety net: every sed edit is committed, the diff shows what changed, and the revert is a git checkout. The etckeeper that the SELinux and hardening articles recommended is the tool that makes the config editing safe on every dimension.
The comparison with the other text-processing tools
Sed, awk, grep and perl are the four text-processing tools that the Unix system provides, and each has its own territory. Grep filters, sed substitutes, awk aggregates and perl does everything. The sed that substitutes in files is the tool for the config editing, and the awk that aggregates from files is the tool for the log analysis. The perl that does both is the tool for the complex transformations that neither sed nor awk can express, and the perl one-liner is the tool of last resort for the text processing that the simpler tools cannot handle.
The choice among them for a specific task follows the complexity of the transformation: the simple substitution is sed, the pattern-based aggregation is awk, the complex transformation is perl, and the choice that the script makes is the one that keeps the script readable, because the readable script is the one that the next person can maintain.
The sed that the config editing uses is the tool that the configuration management complements: the sed for the ad-hoc change, the Ansible for the permanent configuration. The ad-hoc sed that fixes a broken config is the tool that the incident needs.
The comparison with the other text-processing tools: grep filters, sed substitutes, awk aggregates and perl does everything. The choice follows the complexity of the transformation.
The sed that edits the production config file can break the server, and the safety patterns prevent the breakage. The stdout preview, the .bak backup and the config validation after the edit are the three patterns.
The final thought: the sed tool is not clever, not modern, and works. The tool that every server has, the syntax that every administrator knows, and the operation that takes one command.
It works.
Everywhere.