删除带分隔符的多行字符串的后缀

Remove suffix of a delimited multiline string

在尝试安全处理文件名和安全处理换行符的脚本时,我遇到了一个困难的测试用例。

给定输入

a.b.c
.d.staging

这个输入代表一个文件名,我想去掉 .staging 后缀。我通常会为此使用类似于 | rev | cut -d. -f2- | rev 的东西,但这失败了:

echo -ne "a.b.c\n.d.staging" | rev | cut -d. -f2- | rev

产量

a.b
.d

除了丢失 c 组件和 staging 后缀外,末尾还有一个单独的换行符隐藏在 Markdown 中。

到目前为止,我想出的最佳解决方案是使用 sed -e ':a' -e 'N' -e '$!ba' -e 's/\(.*\)\..*//',这似乎有效:

echo -ne "a.b.c\n.d.staging" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\(.*\)\..*//'

产量

a.b.c
.d

这是正确的输出。

这似乎是一个不雅的解决方案,因为它正在 sed 处理换行符,这是 sed 不擅长做的事情。

有没有更优雅的方案?最好是 POSIX 兼容的。

如果变量中有名称,则换行不是问题。

$ fname=$'a.b.c\n.d.staging'
$ echo "$fname"
a.b.c
.d.staging
$ echo "${fname%.*}"
a.b.c
.d
$

使用BASH你可以做到:

$> s=$'a.b.c\n.d.staging'

$> echo "$s"
a.b.c
.d.staging

$> echo "${s%.staging}"
a.b.c
.d

如果没有 BASH 支持,您可以像这样使用 awk using null RS:

printf "%b" 'a.b.c\n.d.staging' | awk -v RS= '{sub(/\.[^.]+$/, "")} 1'

a.b.c
.d