如何从Bash数组元素中移除数字下划线前缀?
问题描述
我有如下Bash数组:
names=( 12_1_3_4_NAME1 1_2_4_NAME2 2_1_name3 1_nAmE4)
希望移除每个元素开头的数字下划线组成的前缀,得到:
names=( NAME1 NAME2 name3 nAmE4 )
我尝试了以下写法但未成功:
names=( "${names[@]/^\d+(?:\_\d+)/}" ) names=( "${names[@]//s*^\d+(?:\_\d+)+\s*/}" )
不清楚如何在Bash数组中正确实现该操作。
可行解决方案
Bash的参数展开不支持Perl风格正则(比如\d、非捕获组(?:...)),仅支持POSIX基本正则表达式,且参数展开的单斜杠替换默认匹配字符串开头,无需额外加^。下面是两种可行实现方式:
方法1:开启extglob扩展后用参数展开
先开启Bash的extglob扩展(支持+(pattern)语法,匹配一个或多个指定模式):
shopt -s extglob
然后直接批量处理数组元素:
names=( "${names[@]//+([0-9]_)/}" )
这条命令会把每个元素开头所有数字+下划线的重复片段替换为空,刚好符合需求。
方法2:循环结合sed处理
如果不想开启extglob,可以用循环遍历数组,通过sed处理每个元素:
new_names=() for name in "${names[@]}"; do new_names+=( "$(sed 's/^\([0-9]\+_\)\+//' <<< "$name")" ) done names=( "${new_names[@]}" )
sed的正则^\([0-9]\+_\)\+表示匹配开头一个或多个数字串+下划线的组合,替换为空后就得到目标字符串。
原写法失败原因
- Bash不支持
\d,需用[0-9]或[[:digit:]]表示数字 - 不支持非捕获组
(?:...),extglob的+(...)是等价的多次匹配语法 - 原写法中多余的
s*和\s*属于错误匹配,原数组元素开头没有空白字符 - 参数展开的替换语法中,单斜杠
/是只替换一次匹配,双斜杠//是全局替换,但这里需要匹配重复的前缀,所以要用全局替换或extglob的多次匹配
内容的提问来源于stack exchange,提问作者Gabriel G.
相关产品推荐
相关产品推荐

