In shell, split a portion of a string with dot as

2020-08-13 01:41发布

问题:

I am new to shell scripting, can you please help with below requirement, thanks.

$AU_NAME=AU_MSM3-3.7-00.01.02.03
#separate the string after last "-", with "." as delimiter
#that is, separate "00.01.02.03" and print/save as below.
major=00
minor=01
micro=02
build=03

回答1:

First, note that you don't use $ when assigning to a parameter in the shell. Your first line should be just this:

AU_NAME=AU_MSM3-3.7-00.01.02.03

Once you have that, then you can do something like this:

IFS=. read major minor micro build <<EOF
${AU_NAME##*-}
EOF

where the ##*- strips off everything from the beginning of the string through the last '-', leaving just "00.01.02.03", and the IFS (Internal Field Separator) variable tells the shell where to break the string into fields.

In bash, zsh, and ksh93+, you can get that onto one line by shortening the here-document to a here-string:

IFS=. read major minor micro build <<<"${AU_NAME##*-}"

More generally, in those same shells (or any other shell that has arrays), you can split into an arbitrarily-sized array instead of distinct variables. This works in the given shells:

IFS=. components=(${AU_NAME##*-})

In older versions of ksh you can do this:

IFS=. set -A components ${AU_NAME##*-}

That gets you this equivalence (except in zsh, which by default numbers the elements 1-4 instead of 0-3):

major=${components[0]}
minor=${components[1]}
micro=${components[2]}
build=${components[3]}


回答2:

In bash, you can do something like this:

version=$(echo $AU_NAME | grep -o '[^-]*$')
major=$(echo $version | cut -d. -f1)
minor=$(echo $version | cut -d. -f2)
micro=$(echo $version | cut -d. -f3)
build=$(echo $version | cut -d. -f4)

The grep call uses -o which outputs only the matching part of the line. The match itself is every non-hyphen character to the end of the line.

The cut command uses the delimeter . (-d.), and uses -f to select individual fields.

It's a little clunky. I'm sure there are probably better ways to achieve this, but you can do quite a lot with grep and cut alone so they're handy tools to have in your arsenal.



回答3:

You can use parameter expansion and the special IFS variable.

#! /bin/bash
AU_NAME=AU_MSM3-3.7-00.01.02.03
IFS=. VER=(${AU_NAME##*-})
for i in {0..3} ; do
    echo ${VER[i]}
done

major=${VER[0]}
minor=${VER[1]}
micro=${VER[2]}
build=${VER[3]}

BTW, in an assignment, do not start the variable on the left hand side with a dollar sign.