Every command, what it does, and the rules it follows. man envctl and envctl <cmd> --help carry the same reference, generated from the same table the parser
validates against.
envctl get [file] <KEY> # print the active value, exit 1 if unset
envctl list [file] # print active key names
envctl list [file] --values # print KEY=VALUE
envctl list [file] --all # include commented keys, tagged (disabled)
envctl list [file] --sort # key order instead of file orderget prints the decoded value followed by a newline: MESSAGE="hello\nworld"
prints two lines, and MESSAGE="say \"hello\"" prints say "hello". The file
format below defines quoting, escapes, and comments. Malformed quoted values
exit 2 without printing a partial value. get --env returns the environment
value as stored. list --values shows the file spelling, including quotes and
escapes, and prints the first line of an unmasked multiline value.
envctl set [file] <KEY> [VALUE] # create or replace
envctl disable [file] <KEY> # comment out, keep the value
envctl enable [file] <KEY> # uncomment
envctl delete [file] <KEY> # remove active and commented alikeAliases: rm for delete, ls for list.
VALUE is literal input. set adds file quoting and escapes when needed so
get returns that same value, including quotes, backslashes, comments, and
newlines supplied as data. Nothing evaluates it as shell syntax or a regex. An
omitted VALUE writes an empty value.
- Update the first active definition in place.
- Comment out any further active duplicates.
- If no active definition exists, revive the first commented one.
- Failing all of that, append the assignment.
Running the same set twice changes nothing the second time.
--dry-run prints a unified diff and writes nothing:
$ envctl --dry-run set .env FOO two
--- .env
+++ .env
@@ -1,1 +1,1 @@
-FOO=one
+FOO=twoOnly changed lines appear. When the command would change nothing, stdout stays
empty and envctl: no changes goes to stderr. Under --redact both sides are
masked and the header reads +++ .env (redacted).
envctl get --env DATABASE_URL # like get, but from the environment
envctl list --env # key names in environ order
envctl list --env --values # values, under the redact rules
envctl env # the whole environment, always redactedenvctl env is the safe one-word replacement for env:
$ envctl env
PATH=/usr/bin:/bin
API_TOKEN=<redacted>Names outside [A-Za-z_][A-Za-z0-9_]* are skipped, which drops bash's exported
functions. envctl env masks unconditionally by default. An explicit
--redact=WHEN replaces that default, so --redact=agent leaves the dump
unmasked when no agent is detected. --redact=never drops the masking but still
escapes control bytes on a terminal; --raw drops both.
some-command 2>&1 | envctl redactredact reads stdin and writes stdout with secrets masked. See
redaction.md for what it looks for and how the env file feeds
it.
If the first positional is an existing path, it is used. Otherwise ./.env is
assumed when it exists as a regular file:
envctl list
envctl get DATABASE_URL
envctl set DEBUG trueRead commands accept any openable path, including FIFOs from process
substitution and /dev/fd/N, so envctl redact <(sops -d secrets.env) works.
Mutating commands rewrite the target atomically and therefore need a regular
file; anything else fails with not a regular file.
envctl [file] <KEY> # get
envctl [file] <KEY> <VALUE> # setA command name always beats a same-named file or key. So envctl .env get X is
a get, and a key literally named env, completions, or module needs the
explicit form envctl get env.
| Flag | Applies to | Effect |
|---|---|---|
--dry-run |
set, disable, enable, delete | Print a unified diff, write nothing |
--values |
list | Show values |
--all |
list, not with --env |
Include commented keys, tagged (disabled) |
--sort |
list, env | Key order instead of file or environ order |
--env |
get, list, redact | Use the process environment instead of a file |
--no-env |
redact | Skip the env file's literal values, heuristics only |
--redact[=WHEN] |
all but completions, module | Choose when masking applies, see redaction.md |
--raw |
all but redact, completions, module | Shorthand for --redact=never --show-control-chars |
--show-control-chars |
all but redact, completions, module | Print control bytes as they are |
--paranoid |
all but completions, module | Apply the entropy bar whatever the key is called |
A flag outside its row is a usage error naming where it belongs:
$ envctl get --values FOO
envctl: --values is only valid for listredact takes a file, --env, or --no-env, never two of them. --paranoid
implies --redact and rejects --raw.
envctl -h # short usage
envctl --help # long help
envctl get --help # one command, with only the flags it accepts
man envctl # full reference
envctl --version # the version this binary was built fromenvctl get --help and envctl --help get do the same thing, since the command
word is found wherever it sits.
| Kind | Shape |
|---|---|
| Active | optional whitespace and export, then KEY=... |
| Commented | leading #, optional whitespace, then the same |
Keys must match [A-Za-z_][A-Za-z0-9_]*. Spaces and tabs around the key and =
are accepted. A UTF-8 byte order mark before an assignment is ignored.
- Unquoted values lose leading and trailing spaces and tabs.
#starts a comment when preceded by a space or tab:KEY=value # notereadsvalue, whileKEY=value#suffixandKEY=#prefixkeep the hash. Backslashes stay literal in unquoted values. - Single-quoted values decode
\\and\'. Other escapes stay literal. - Double-quoted values decode
\\,\",\',\a,\b,\f,\n,\r,\t, and\v. Unknown escapes retain their backslash. - Backtick-quoted values decode an escaped backtick or backslash; other escapes stay literal. Backticks are value delimiters and never run commands.
Whitespace inside quotes is preserved. After a closing quote, only spaces, tabs,
and an optional # comment are allowed. Variable references such as $NAME and
${NAME} stay literal; reading a value does not interpolate the process
environment or evaluate shell expressions.
A value that opens a quote (", ', `) or a -----BEGIN block runs
until its terminator, up to 512 lines. Those continuation lines belong to the
key, so set, disable, enable, and delete move all of them together.
Mutating a key whose value never terminates writes nothing and exits non-zero.
A file containing a NUL byte is rejected rather than silently truncated there.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | get found no active definition of the key |
| 2 | Usage error, unreadable or unwritable file, or a failed write to stdout |
- Only the target key's logical assignment changes, continuation lines included.
- Order, comments, spacing, and unrelated lines survive untouched.
- Writes are atomic (temp file plus rename) and preserve the file mode.
- Redaction never applies to what lands on disk.