4

I need to split a string into an array. My problem is that the delimiter is a 3 character one: _-_

For example:

db2-111_-_oracle12cR1RAC_-_mariadb101

I need to create the following array:

db2-111
oracle12cR1RAC
mariadb101

Similar questions followed this approach:

str="db2-111_-_oracle12cR1RAC_-_mariadb101"
arr=(${str//_-_/ })
echo ${arr[@]}

Even if the array is created, it has been split incorrectly:

db2 
111 
oracle12cR1RAC 
mariadb101

It seems that the "-" character in the first item causes the array's split function to fail.

Can you suggest a fix for it? Thanks.

1
  • Related question in case the input also contains line breaks. Commented Dec 31, 2024 at 0:50

5 Answers 5

3

If you can, replace the _-_ sequences with another single character that you can use for field splitting. For example,

$ str="db2-111_-_oracle12cR1RAC_-_mariadb101"
$ str2=${str//_-_/#}
$ IFS="#" read -ra arr <<< "$str2"
$ printf '%s\n' "${arr[@]}"
db2-111
oracle12cR1RAC
mariadb101
Sign up to request clarification or add additional context in comments.

Comments

2

You could use sed to do what you want, i.e. writting something like that :

str="db2-111_-_oracle12cR1RAC_-_mariadb101"
arr=($(sed 's/_-_/ /g' <<< $str))
echo ${arr[0]}

Edit :

The reason arr=(${str//_-_/ }) didn't work is that when you write it like that, everything inside ${ ... } is considered as 1 element of the array. So, using sed, or even simply arr=($(echo ${str//_-_/ })) will produce the result you expect.

6 Comments

Thanks for the suggestion. I've tried it though and it produces a 1 sized array unfortunately: echo ${arr[0]} db2 111 oracle12cR1RAC mariadb101
Using escapes didn't work either sed "s/\_\-\_/ /g"
Are you sure you are using the exact code I gave? Copy/pasting my code works on zsh, bash-4.4 and bash-3.2 on my computer (using GNU sed)
Indeed a bit weird. The code is the same. I'm running bash 4.3.43(1) release
@FrancescoMarchioni That's the output you'll get in bash 4.3 if you have IFS="_-_", which seems like something you might have tried and forgot to reset. This code assumes that IFS has its default value.
|
2
<<<'db2-111_-_oracle12cR1RAC_-_mariadb101' | 

{m,g}awk NF=NF FS='_[-]_' OFS='\n'

db2-111
oracle12cR1RAC
mariadb101

if you like the fringe but ultra concise RS syntax, it's

mawk ~ RS='_-_|\n'

   or

mawk \$_ RS='_-_|\n'

   or simply

mawk RS RS='_-_|\n'

db2-111
oracle12cR1RAC
mariadb101

Comments

0

Using Perl one-liner

$ echo "db2-111_-_oracle12cR1RAC_-_mariadb101" | perl -F/_-_/ -ne ' { print "$F[0]\n$F[1]\n$F[2]" } '
db2-111
oracle12cR1RAC
mariadb101

Comments

0

Here is a solution using replacement of _-_ with a NUL byte since we cannot make a safe assumption that some character like # or ; or : will not be present in input strings.

readarray -d '' arr < <(
   awk -F'_-_' -v OFS='\0' '{ORS=OFS; $1=$1} 1' <<< "$str")

declare -p arr
declare -a arr=([0]="db2-111" [1]="oracle12cR1RAC" [2]="mariadb101")

Note that due to use of readarray it will require BASH ver 4+

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.