Bash 字符串用一个字符替换多个字符

Bash 字符串用一个字符替换多个字符

我将提要标题中除字母和数字之外的所有字符替换为破折号,以将结果用作任何文件系统的安全文件名:

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ echo ${t//[^A-Za-z0-9]/-}
Episodie-06--No-hope-of-riding-home--NEW----Advanced-grammar

不过,我想将所有重复的破折号压缩为一个破折号,例如Episodie-06-No-hope-of-riding-home-NEW-Advanced-grammar

我发现我可以使用两遍替换来实现它:

$ t="Episodie 06: No hope of riding home (NEW) - Advanced grammar"
$ tmp=${t//[^A-Za-z0-9]/-}
$ echo ${tmp//--/-}
Episodie-06-No-hope-of-riding-home-NEW--Advanced-grammar

我想我可以一次性完成它,例如:

$ echo ${t//[^A-Za-z0-9]+/-}

但它不起作用。

有什么线索吗?

注意:我不想使用sed或其他工具

答案1

您需要比传统 shell 通配符更强大的东西。在 bash 中,设置该extglob选项,该选项使您可以访问以下中的正则表达式全局模式通过从 ksh 继承的不寻常语法。

shopt -s extglob
sanitized=${raw//+([^A-Za-z0-9])/-}

答案2

tr是这项工作的好工具

new=$( printf "%s" "$t" | tr -cs 'a-zA-Z0-9' '-' )
new=${new#-}; new=${new%-}

答案3

如果您想继续使用纯 bash,则必须采用两遍解决方案。 Bash 字符串替换使用球体,如路径名扩展中所示,以及不是常用表达。 glob 中唯一的特殊字符是*?、 和[],它们在正则表达式中的粗略等效字符是.*.[]。看看伍利奇 维基百科以及有关和bash(1)的手册页部分以获取更多信息。Parameter ExpansionPathname Expansion

正如评论一样,纯 bash 中的两遍扩展仍然可能比尝试通过调用外部程序来做同样的事情更快,所以我不会太担心。

相关内容