Bash脚本 - 使用正则表达式分割字符串

6

我希望能够拆分类似于“substring1 substring2 ONCE[0,10s] substring3”这样的字符串。预期结果应该是(使用分隔符“ONCE[0,10s]”):

substring1 substring2
substring3

问题是分隔符中的数字是变量,例如'ONCE [0,1s]'或 'ONCE [0,3m]'或'ONCE [0,10d]'等等。
如何在bash脚本中实现这一点?有任何想法?
谢谢
3个回答

6

OP提供的示例(以及@GlennJackman和@devnull提供的两个答案)假设实际问题可能是:

在bash中,如何将字符串中正则表达式的匹配项替换为换行符。

这实际上并不同于“使用正则表达式拆分字符串”,除非您添加约束条件,即该字符串不包含任何换行符。 即使这样,它也不会真正“拆分”字符串; 假设某些其他进程将使用换行符来拆分结果。

一旦问题被重新制定,解决方案就不具有挑战性了。您可以使用支持正则表达式的任何工具,例如sed

sed 's/ *ONCE\[[^]]*] */\n/g' <<<"$variable"

(如果只想替换第一序列,请删除g; 若想更改正则表达式以满足需求,需要进行相应的调整。)
bash本身不提供使用正则表达式进行全局替换的基本操作,虽然它拥有“模式”。如果设置了选项extglob(在某些发行版上是默认的),这些模式就足够强大,可以表达该模式,因此您可以使用以下命令:
echo "${variable//*( )ONCE\[*([^]])]*( )/$'\n'}"

再次提醒,您可以通过将//更改为/来仅进行一次替换,并且您可能需要更改模式以满足您的精确需求。

这就留下了一个问题,即如何使用由正则表达式指定的分隔符实际拆分bash变量,对于某些定义的“拆分”。 一个可能的定义是“使用字符串部分作为参数调用函数”; 这就是我们在这里使用的方式:

# Usage:
# call_with_split <pattern> <string> <cmd> <args>...
# Splits string according to regular expression pattern and then invokes
# cmd args string-pieces
call_with_split () { 
  if [[ $2 =~ ($1).* ]]; then
    call_with_split "$1" \
                    "${2:$((${#2} - ${#BASH_REMATCH[0]} + ${#BASH_REMATCH[1]}))}" \
                    "${@:3}" \
                    "${2:0:$((${#2} - ${#BASH_REMATCH[0]}))}"
  else
    "${@:3}" "$2"
  fi
}

例子:

$ var="substring1 substring2 ONCE[0,10s] substring3"
$ call_with_split " ONCE\[[^]]*] " "$var" printf "%s\n"
substring1 substring2
substring3

5

bash:

s='substring1 substring2 ONCE[0,10s] substring3'

if [[ $s =~ (.+)" ONCE["[0-9]+,[0-9]+[smhd]"] "(.+) ]]; then
    echo "${BASH_REMATCH[1]}"
    echo "${BASH_REMATCH[2]}"
else 
    echo no match
fi

substring1 substring2
substring3

2
你可以使用 awk。将字段分隔符指定为:
'ONCE[[]0,[^]]*[]] *'

例如,使用您的示例输入:
$ awk -F 'ONCE[[]0,[^]]*[]] *' '{for(i=1;i<=NF;i++){printf $i"\n"}}' <<< "substring1 substring2 ONCE[0,10s] substring3"
substring1 substring2 
substring3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接