..
envsubst 在 perl 的实现
代码来源: https://metacpan.org/source/PEVANS/String-Expand-0.04/lib/String/Expand.pm
#!/usr/bin/env perl
my $VARNAME_MATCH = qr/\$([A-Z_][A-Z0-9_]*|\{.*?\})/;
sub expand_one_var($$)
{
my ( $var, $vars ) = @_;
# Chop off delimiting {braces} if present
$var =~ s/^\{(.*)\}$/$1/;
unless( defined $vars->{$var} ) {
die "Unknown variable '$var'";
}
return $vars->{$var};
}
sub expand_string($$)
{
my ( $str, $vars ) = @_;
$str =~ s{\\([\\\$])|$VARNAME_MATCH}
{ $1 or expand_one_var( $2, $vars )}eg;
return $str;
}
sub expand_strings_inner($$$$);
sub expand_strings_one_var($$$$)
{
my ( $var, $strs, $overlay, $done ) = @_;
# Chop off delimiting {braces} if present
$var =~ s/^\{(.*)\}$/$1/;
if( exists $strs->{$var} ) {
return $strs->{$var} if( $done->{$var} );
# Detect loops
if( exists $done->{$var} ) {
die "Variable loop trying to expand '$var'";
}
$done->{$var} = 0;
expand_strings_inner( $strs, $overlay, $var, $done );
return $strs->{$var};
}
return $overlay->{$var} if( exists $overlay->{$var} );
die "Unknown variable '$var'";
}
sub expand_strings_inner($$$$)
{
my ( $strs, $overlay, $v, $done ) = @_;
if( $strs->{$v} =~ m/[\\\$]/ ) {
$strs->{$v} =~ s{\\([\\\$])|$VARNAME_MATCH}
{ $1 or expand_strings_one_var( $2, $strs, $overlay, $done )}eg;
}
$done->{$v} = 1;
}
sub expand_strings($$)
{
my ( $strs, $overlay ) = @_;
# 0: a variable expansion is in progress
# 1: value has been correctly expanded
my %done;
foreach my $v ( keys %$strs ) {
expand_strings_inner( $strs, $overlay, $v, \%done );
}
}
my $str = "hello $USER";
print expand_string($str,%ENV) . "\n";