Skip to content

Conversation

@nicholasklem
Copy link

Summary

This PR adds support for GNU envsubst's SHELL-FORMAT positional argument, enabling selective variable substitution while preserving the extended bash-style syntax that makes this library valuable.

Use case: In ArgoCD Config Management Plugins, we need to:

  1. Only substitute ARGOCD_ENV_* prefixed variables (not all env vars)
  2. Use default value syntax like ${VAR:-default}

Currently, users must choose between GNU envsubst (variable filtering) OR a8m/envsubst (extended syntax). This PR enables both.

Changes

  • SHELL-FORMAT positional argument: envsubst '$VAR1 $VAR2' only substitutes listed variables
  • -v flag: Outputs variable names from SHELL-FORMAT (GNU compatibility)
  • New public API: StringWithVars(), BytesWithVars(), ReadFileWithVars() and restricted variants
  • Full backward compatibility: No SHELL-FORMAT = substitute all (existing behavior)

Example Usage

# Only substitute $USER and $HOME, leave $OTHER as literal
echo '$USER $HOME $OTHER' | envsubst '$USER $HOME'
# Output: alice /home/alice $OTHER

# Extended syntax preserved for filtered variables
echo '${FOO:-default} ${BAR:-default}' | envsubst '$FOO'
# Output: foovalue ${BAR:-default}

# ArgoCD use case - only substitute ARGOCD_ENV_* vars
kustomize build . | envsubst "$(env | awk -F '=' '/ARGOCD_ENV_/ {printf("$%s ",$1)}')"

Test plan

  • All existing tests pass
  • New unit tests for SHELL-FORMAT parsing
  • New integration tests for variable filtering
  • Manual CLI verification

We understand this is a significant change. Happy to discuss the approach or make adjustments based on feedback. We have a fork at nicholasklem/envsubst if this doesn't align with the project's direction.

🤖 Generated with Claude Code

nicholasklem and others added 2 commits January 12, 2026 18:39
Add support for GNU envsubst's SHELL-FORMAT positional argument, enabling
selective variable substitution while preserving the extended bash syntax.

When SHELL-FORMAT is provided (e.g., `envsubst '$FOO $BAR'`), only those
variables are substituted; other variable references remain as literal text.

New features:
- SHELL-FORMAT positional argument for variable filtering
- `-v` flag to output variable names from SHELL-FORMAT (GNU compat)
- New public API: StringWithVars(), BytesWithVars(), ReadFileWithVars()
- Full backward compatibility when no SHELL-FORMAT is provided

Example usage:
  # Only substitute $USER and $HOME, leave others literal
  echo '$USER $HOME $OTHER' | envsubst '$USER $HOME'

  # Works with extended syntax - preserves defaults for filtered vars
  echo '${FOO:-default} ${BAR:-default}' | envsubst '$FOO'
  # Output: foovalue ${BAR:-default}

  # List variables in SHELL-FORMAT
  envsubst -v '$FOO ${BAR}'
  # Output: FOO\nBAR

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive test cases for SHELL-FORMAT parsing:
- Escaping ($$, $$$$)
- Underscore handling (_FOO vs _)
- All operator variants (:-  :=  :+  -  =  +)
- Edge cases (trailing $, unclosed braces, empty input)
- Numeric vars (a8m allows by default, unlike GNU)
- Real-world ARGOCD_ENV_ patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@nicholasklem nicholasklem marked this pull request as draft January 16, 2026 12:22
@nicholasklem
Copy link
Author

I moved away from SHELL-FORMAT and went with a -prefix option instead in PR #73 . Closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant