diff --git a/envsubst/funcs.go b/envsubst/funcs.go index a9b6f3298..328cb1d24 100644 --- a/envsubst/funcs.go +++ b/envsubst/funcs.go @@ -121,6 +121,18 @@ func toSubstr(s string, args ...string) string { return s } + if length < 0 { + // a negative length counts back from the end of the string, so + // ${var:1:-1} drops the first and the last character. + end := len(s) + length + if end < pos { + // bash rejects this as a negative substring expression. + return "" + } + + return s[pos:end] + } + if pos+length >= len(s) { if pos < len(s) { // if the position exceeds the length of the diff --git a/envsubst/funcs_test.go b/envsubst/funcs_test.go index 66b05856c..fc5a30300 100644 --- a/envsubst/funcs_test.go +++ b/envsubst/funcs_test.go @@ -121,4 +121,24 @@ func Test_substr(t *testing.T) { if got != want { t.Errorf("Expect substr function to cut entire string if pos is itself out of bound") } + + got, want = toSubstr("hello world", "2", "-1"), "llo worl" + if got != want { + t.Errorf("Expect substr function to count a negative length back from the end, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "0", "-3"), "hello wo" + if got != want { + t.Errorf("Expect substr function to count a negative length back from the end at offset 0, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "8", "-8"), "" + if got != want { + t.Errorf("Expect substr function to return empty when a negative length ends before the offset, got %q want %q", got, want) + } + + got, want = toSubstr("hello world", "-4", "-1"), "orl" + if got != want { + t.Errorf("Expect substr function to combine a negative offset with a negative length, got %q want %q", got, want) + } }