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

use*_*984 5 regex string bash split sh

我想拆分像'substring1 substring2 ONCE[0,10s] substring3'这样的字符串。预期结果应该是(使用分隔符“ONCE[0,10s]”):

substring1 substring2
substring3
Run Code Online (Sandbox Code Playgroud)

问题是分隔符中的数字是可变的,例如 'ONCE[0,1s]' 或 'ONCE[0,3m]' 或 'ONCE[0,10d]' 等等。

我怎样才能在 bash 脚本中做到这一点?任何的想法 ?

谢谢

gle*_*man 5

重击:

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
Run Code Online (Sandbox Code Playgroud)
substring1 substring2
substring3
Run Code Online (Sandbox Code Playgroud)


ric*_*ici 5

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

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

这实际上与“使用正则表达式拆分字符串”不同,除非您添加字符串不包含任何换行符的约束。即便如此,它实际上并没有“拆分”字符串;假设是其他一些进程将使用换行符来分割结果。

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

sed 's/ *ONCE\[[^]]*] */\n/g' <<<"$variable"
Run Code Online (Sandbox Code Playgroud)

g如果您只想替换第一个序列,请删除;您可能需要调整正则表达式,因为不太清楚所需的约束是什么。)

bash本身不提供replace all使用正则表达式的原语,尽管它确实具有“模式”,并且如果extglob设置了该选项(这是某些发行版的默认设置),则模式足以表达模式,因此您可以使用:

echo "${variable//*( )ONCE\[*([^]])]*( )/$'\n'}"
Run Code Online (Sandbox Code Playgroud)

同样,您可以通过更改//为使替换只发生一次,/并且您可能需要更改模式以满足您的确切需求。

这留下了一个问题,即如何使用正则表达式指定的分隔符实际拆分 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
}
Run Code Online (Sandbox Code Playgroud)

例子:

$ var="substring1 substring2 ONCE[0,10s] substring3"
$ call_with_split " ONCE\[[^]]*] " "$var" printf "%s\n"
substring1 substring2
substring3
Run Code Online (Sandbox Code Playgroud)


dev*_*ull 2

你可以使用awk. 将字段分隔符指定为:

'ONCE[[]0,[^]]*[]] *'
Run Code Online (Sandbox Code Playgroud)

例如,使用您的示例输入:

$ awk -F 'ONCE[[]0,[^]]*[]] *' '{for(i=1;i<=NF;i++){printf $i"\n"}}' <<< "substring1 substring2 ONCE[0,10s] substring3"
substring1 substring2 
substring3
Run Code Online (Sandbox Code Playgroud)