Pure Bash替换捕获组

时间:2016-11-23 20:43:04

标签: regex bash replace

我有这个示例字符串:

test_string="13A6"

此字符/数字可以是0到9以及从A到F.

我想要这个输出:

1 3 A 6

我有这个工作:

result=$(echo ${test_string} | sed 's/./& /g')

我想在没有sed的情况下这样做...我有另一个解决方案,我不太喜欢......很脏:S

[[ ${test_string} =~ ^([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F]) ]] && result="${BASH_REMATCH[1]} ${BASH_REMATCH[2]} ${BASH_REMATCH[3]} ${BASH_REMATCH[4]}"

如果可能的话,我希望使用语法为result=${variable//pattern/replacement}的纯bash但不确定如何做"&"在sed中引用匹配的char本身就是这种纯粹的bash语法。任何bash大师? :)

2 个答案:

答案 0 :(得分:4)

这个怎么样(没有调用外部工具):

str="13A6"
[[ $str =~ ${str//?/(.)} ]]
printf '%s\n' "${BASH_REMATCH[*]:1}"

结果(没有尾随空格):

"1 3 A 6"

或者,如果您需要使用其他分隔符:

[[ $str =~ ${str//?/(.)} ]]
( IFS=$'\n'; printf "%s\n" "${BASH_REMATCH[*]:1}")

或者,在函数中,IFS可能是函数的本地函数:

divide(){ 
    [[ $1 =~ ${1//?/(.)} ]]
    local IFS=${2:-' '}
    printf '%s\n' "${BASH_REMATCH[*]:1}"
}

divide "13A6" "-"            # will output 1-3-A-6 in this example.

这样的工作原理如下:

           ${str//?/(.)}              # Replace each character with "(.)".  
[[ $str =~               ]]           # Match the regex "(.)(.)(.) … …"  
                                      # capturing each character matched  
                                      # in the array "${BASH_REMATCH[@]}"  

printf '%s\n' "${BASH_REMATCH[*]:1}"  # Forget array index 0 and
                                      # convert the array to one string 
                                      # using the first character
                                      # of "$IFS" as separator
                                      # (no trailing separator). 

感谢@chepner建议将数组中的@更改为*。这避免了使用时间数组或位置参数的需要。

答案 1 :(得分:0)

我不知道它是否像你想要的那样纯净:

test_string="13A6"
length=$( expr length "$test_string" )
s=""
for (( i=1;i<=${length};i++)) 
do
  c=$( expr substr "${test_string}" $i 1 )
  s=${s}" "$c
done
echo $s

Res:

1 3 A 6

或者在chepner的帮助下最纯粹(没有外部程序)。

test_string="13A6"
s=""
for ((i=0;i<${#test_string};i++))
do
  s=${s}" "${test_string:i:1}
done
echo $s