3

I'm trying to split this string and store substrings in separate variables as follows:

temp="one$two$three$fourfive"
IFS="$" read var1 var2 var3 var4 <<< "$temp"

When I echo var1 I get "one" but when I echo var2 there is no output. It works when I add a '\' before every $ sign but when I try to do it programmatically:

echo "$temp" | sed 's/$/\\$/g'

Output: one\$

How can I fix this?

Inian
  • 80,270
  • 14
  • 142
  • 161
Barath R
  • 199
  • 3
  • 12
  • Or simply create an array of the split values, e.g. `IFS=$'$\n'; array=( $(echo $tmp) )` – David C. Rankin Feb 14 '19 at 09:11
  • 1
    @DavidC.Rankin, test with `tmp='-n$/*'`. – pjh Feb 14 '19 at 19:28
  • Where does `tmp='-n$/*'` come from? I thought the question was `temp="one$two$three$fourfive"`? – David C. Rankin Feb 14 '19 at 21:43
  • Barath R, note that the code in the question (even with the quoting and `read` usage fixes given in the solution by Inian) doesn't work for all possible values of `$temp`. In particular, it fails of the string contains newline characters. Test with `temp=$'a\nb$c$d$e'`. See [How do I split a string on a delimiter in Bash?](https://stackoverflow.com/q/918886/4154375) for many solutions to the general problem. Unfortunately, many of the solutions don't work in all circumstances. The solution by gniourf_gniourf is good. – pjh Feb 15 '19 at 19:36

3 Answers3

4

Your problem is with the original string temp where with double quotes, your rest of the strings two, three and fourfive are interpreted as shell variables.

Using single quotes on the temp string would let the variables to not to be expanded to an empty string.

temp='one$two$three$fourfive'

Also recommend using read with -r flag to not let not backslashes mangle your string

IFS='$' read -r var1 var2 var3 var4 <<< "$temp"
Inian
  • 80,270
  • 14
  • 142
  • 161
3

The problem isn't with reading them, it's when you assigned to temp in the first place. Variables are expanded inside double quotes, so it tries to use the values of $two, $three, etc. Since these variables don't exist, you just did:

temp="one"

You would have noticed this if you simply did:

echo "$temp"

You need to use single quotes instead of double quotes, so variables won't be expanded.

temp='one$two$three$fourfive'
IFS="$" read var1 var2 var3 var4 <<< "$temp"
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

Using read isn't necessary, a bash array would be better than separate variables:

temp='one$two$three$fourfive'
var=(${temp//$/ })
printf '%s\n' ${var[@]}

Output:

one
two
three
fourfive
agc
  • 7,973
  • 2
  • 29
  • 50
  • 1
    Test with `temp='a b$/*'`. – pjh Feb 14 '19 at 19:17
  • @pjh, Thanks, but not unless the OP specifies that the data may [contain `*`s](https://en.wikipedia.org/wiki/Corner_case). Most *nix tools are designed with the presumption that the input data is normal, or at least pre-cleaned. If the data can't be cleaned, a language with [counted strings](https://en.wikipedia.org/wiki/String_(computer_science)#Length-prefixed) would be a win for safety. – agc Feb 14 '19 at 22:29