Skip to content

bug: ${var%$'\\n'} doesn't match newline in suffix removal pattern #847

@chaliy

Description

@chaliy

Problem

${var%$'\n'} and ${var%${nl}} (where nl contains a newline) fail to strip a trailing newline. The ANSI-C quoted $'\n' and variable-held newline are not interpreted correctly as the pattern in % (suffix removal) and related parameter expansion operators.

A literal embedded newline in the pattern does work: ${var%<actual newline>}.

Reproduction

str=$'abc\n'
echo "original: $(printf '%q' "${str}")"
# → $'abc\n'

# BROKEN: $'\n' in pattern
r1="${str%$'\n'}"
echo "ansi-c: $(printf '%q' "${r1}")"
# Expected: abc
# Actual:   $'abc\n'  (not trimmed)

# BROKEN: variable holding newline
nl=$'\n'
r2="${str%${nl}}"
echo "var: $(printf '%q' "${r2}")"
# Expected: abc
# Actual:   $'abc\n'  (not trimmed)

# WORKS: literal newline in pattern
r3="${str%
}"
echo "literal: $(printf '%q' "${r3}")"
# → abc  ✓

Impact

wedow/harness uses ${body%$'\n'} to trim trailing newlines from message bodies when assembling conversation history:

body="${body%$'\n'}"

This is also a common bash idiom used in many scripts.

Test cases

# $'\n' in % suffix removal
str=$'hello\n'
result="${str%$'\n'}"
echo "${result}"
# Expected stdout: hello

# $'\n' in %% longest suffix removal
str2=$'a\n\n'
result2="${str2%%$'\n'}"
echo "${result2}"
# Expected stdout: a

# $'\n' in # prefix removal
str3=$'\nhello'
result3="${str3#$'\n'}"
echo "${result3}"
# Expected stdout: hello

# Variable containing newline in pattern
nl=$'\n'
str4=$'world\n'
result4="${str4%${nl}}"
echo "${result4}"
# Expected stdout: world

# $'\t' in pattern (tab — related)
str5=$'data\t'
result5="${str5%$'\t'}"
echo "${result5}"
# Expected stdout: data

# Multi-char pattern with $'\n'
str6=$'line1\nline2\n'
result6="${str6%$'\n'}"
echo "$(printf '%q' "${result6}")"
# Expected: $'line1\nline2'

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions