如何在bash中拆分和提取字符串

3
我有一个字符串"prod-v4.38"
我想要拆分并获取如下的值:
ENV_NAME=$(echo "$OLD_VERSION" | awk -F'-' '{print $1}')
VER_MAJOR=$(echo "$OLD_VERSION" | awk -F'-' '{print $2}')
VER_MINOR=$(echo "$OLD_VERSION" | awk -F'.' '{print $2}')

echo "ENV_NAME" $ENV_NAME
echo "VER_MAJOR" $VER_MAJOR
echo "VER_MINOR" $VER_MINOR

哪个打印

ENV_NAME prod
VER_MAJOR v4.38
VER_MINOR 38

但是我想要得到:
ENV_NAME prod
VER_MAJOR 4
VER_MINOR 38

然后将三个组合在一起,得到prod-v4.38
5个回答

4
在bash中,使用[[ ... ]]=~操作符可以捕获正则表达式的部分内容,并将其填充到系统的BASH_REMATCH数组中。您可以在正则表达式的部分内容周围使用括号来进行捕获。BASH_REMATCH数组的元素是从第二个元素(索引1)开始的捕获组。第一个元素保存了整个匹配的正则表达式。
在您的情况下,如果您的版本字符串保存在变量str中,您将会有:
[[ $str =~ ^([^-]+)-([^.]+)[.](.*)$ ]]

要在您的bash脚本中使用它,只需确保表达式与str中的内容匹配,可以使用if复合命令。一个简单的示例如下:
#!/bin/bash

str="prod-v4.38"

[[ $str =~ ^([^-]+)-([^.]+)[.](.*)$ ]] || {
  printf "error: '%s' not valid version string.\n"
  exit 1
}

printf "ENV_NAME: %s\nVER_MAJOR: %s\nVER_MINOR: %s\n" \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"

output

$ bash split-ver.sh
ENV_NAME: prod
VER_MAJOR: v4
VER_MINOR: 38

如果你需要使它与POSIX shell兼容,你可以简单地使用参数扩展,例如。
ENV_NAME="${str%-*}"
tmp="${str#"$ENV_NAME"-}"
VER_MAJOR="${tmp%.*}"
VER_MINOR="${tmp#*.}"

3
使用参数扩展,比起调用`awk`要快得多。
#!/bin/bash
old_version='prod-v4.32'
env_name=${old_version%-*}  # Remove "-*" from the right.

version=${old_version#*-v}  # Remove "*-v" from the left.
ver_major=${version%.*}
ver_minor=${version#*.}

echo ENV_NAME "$env_name"
echo VER_MAJOR "$ver_major"
echo VER_MINOR "$ver_minor"

你怎么从包含32的字符串中得到38的,我完全不知道,但也许那是个打字错误?

2
也要检查一下:
OLD_VERSION="prod-v4.38"

IFS='-.' read -r ENV_NAME VER_MAJOR VER_MINOR <<< "$OLD_VERSION"

VER_MAJOR=${VER_MAJOR#v}

echo "ENV_NAME" "$ENV_NAME"
echo "VER_MAJOR" "$VER_MAJOR"
echo "VER_MINOR" "$VER_MINOR"

NEW_VERSION="${ENV_NAME}-v${VER_MAJOR}.${VER_MINOR}"
echo "NEW_VERSION" "$NEW_VERSION"

输出

ENV_NAME prod
VER_MAJOR 4
VER_MINOR 38
NEW_VERSION prod-v4.38

1
你可以使用单个read来完成这个任务。
oldVer="prod-v4.38"
IFS="-." read version verMajor verMinor <<< "$oldVer"
verMajor="${verMajor//[!0-9]}"

# check 3 variables
declare -p version verMajor verMinor

declare -- version="prod"
declare -- verMajor="4"
declare -- verMinor="38"

# combine 3 to get original string
printf -v newVer "%s-v%s.%s" "$version" "$verMajor" "$verMinor"

# check new variable
declare -p newVer

declare -- newVer="prod-v4.38"

1

read更简单。

$ old=prod-v4.38

$ IFS=".-" read -r environ major minor <<< "$old"
$: echo "environ='$environ' major='${major#v}' minor='$minor'"
environ='prod' major='4' minor='38'

$ IFS=".-" read -ra field <<< "$old"
$ echo "env:${field[0]} maj:${field[1]#v} min:${field[2]}"
env:prod maj:4 min:38


通常情况下,每当你发现自己在重复同样的事情时,你应该考虑重构一下。 甚至这样做会更好:
$ mapfile -t field < <( awk -F'[-.]' -v OFS=$'\n' '{print $1,$2,$3}' <<< "$old" )

$ echo "env:${field[0]} maj:${field[1]#v} min:${field[2]}"
env:prod maj:4 min:38

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