24

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
rodee
  • 3,233
  • 5
  • 34
  • 70

3 Answers3

30

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

The $ is used to get the value of the parameter once assigned. And the bit after the $ can be an expression in curly braces with extra stuff besides just the name, allowing you to perform various operations on the value. For example, 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) parameter 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, you can split into an arbitrarily-sized array instead of distinct variables:

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

(Though that syntax won't work in especially-ancient versions of ksh; in them you have to do this instead:

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]}
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
21

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.

paddy
  • 60,864
  • 6
  • 61
  • 103
4

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.

choroba
  • 231,213
  • 25
  • 204
  • 289