-1

I'm trying to split strings based on "##" characters. The challenge is the number of occurrences of "#" is not always 2. I can get up to 5 occurrences at times.

If it was a static occurrences like '##' or '###' I would have used:

IFS="##" read -ra var1 <<< "$var" 

Here is my string:

Strin1##String2###String3##String4#####String5 

Currently I'm following IFS="##", later remove all the occurrences of '#'. However I'm looking for a code way to support this.

agc
  • 7,973
  • 2
  • 29
  • 50
Ashwin
  • 439
  • 1
  • 7
  • 23
  • Please clarify whether `var=foo####bar` represents an array of *two* items, or *three*, (the middle item a blank string). – agc Feb 10 '19 at 16:52
  • i do not have any control over the variable var. It can be array of more than two items. – Ashwin Feb 11 '19 at 05:31
  • It's a hypothetical question. **Suppose** that `var=foo####bar`. Now, *supposing* that, please tell us if `$var1` ought to have *two* items, or *three*. – agc Feb 11 '19 at 07:18

2 Answers2

1

bash has parameter transformation operators to help debug problems like this:

var='Strin1##String2###String3##String4#####String5'
IFS="##" read -ra var1 var2 var3 var4 var5 var6 <<< "$var"
echo ${var1[@]@A}

...which uses the Assignment operator to print a declare statement showing what's really in the array $var1:

declare -a var1=([0]="Strin1" [1]="" [2]="String2" [3]="" [4]="" [5]="String3" [6]="" [7]="String4" [8]="" [9]="" [10]="" [11]="" [12]="String5")

There's thirteen items, which corresponds to each "side" of the twelve #s in the $var string. This is because the $IFS variable does not understand user-assigned strings, it only looks at those individual characters in a string. So IFS="#######" and IFS="##" and IFS="#" are all equivalent, at least so far as read is concerned.

The simplest fix is to first run $var through tr's squeeze function to remove the repeating #s:

var='Strin1##String2###String3##String4#####String5'
IFS="#" read -ra var1 var2 var3 var4 var5 var6 <<< "$(tr -s '#' <<< "$var")"
echo ${var1[@]@A}

Which outputs:

declare -a var1=([0]="Strin1" [1]="String2" [2]="String3" [3]="String4" [4]="String5")
agc
  • 7,973
  • 2
  • 29
  • 50
-1

You can use a regex on IFS

IFS="##[#]*" read -ra var1 <<< "Strin1##String2###String3##String4#####String5"

When you print var1 array, you'll get

Strin1 String2 String3 String4 String5
Lili Sousa
  • 81
  • 1
  • 6
  • 1
    That doesn't work for the reason you think it does. `IFS` specifies a collection of characters; ordering and repetition makes no difference at all. If you specify `IFS=abc`, then `abc123abc` behaves just the same as `aaa123aaa` or `cba123cba` or `a123b`. – Charles Duffy Feb 10 '19 at 22:30
  • 1
    ...so, all you're doing with `IFS='##[#]*'` is telling `[` and `*` to be special in addition to `#`. – Charles Duffy Feb 10 '19 at 22:32
  • 1
    See the above assertions demonstrated in the transcript at https://ideone.com/nCfm03 – Charles Duffy Feb 10 '19 at 22:36