删除带分隔符的多行字符串的后缀
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
在尝试安全处理文件名和安全处理换行符的脚本时,我遇到了一个困难的测试用例。
给定输入
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