Search code examples
bashsplitifs

How do you split a string from shell-redirect or `read`?


I'm trying to split key value pairs (around an = sign) which I then use to edit a config file, using bash. But I need an alternative to the <<< syntax for IFS.

The below works on my host system, but when i log in to my ubuntu virtual machine through ssh I have the wrong bash version. Whatever I try, <<< fails. (I am definitely calling the right version of bash at the top of the file, using #!/bin/bash (and I've tried #!/bin/sh etc too)).

I know I can use IFS as follows on my host mac os x system:

var="word=hello"        
IFS='=' read -a array <<<"$var"
echo ${array[0]} ${array[1]]}

#alternative -for calling through e.g. sh file.sh param=value
for var in "$@"
    do      
    IFS='=' read -a array <<<"$var"
    echo ${array[0]} ${array[1]]}
done


#alternative
  IFS='=' read -ra array <<< "a=b"
  declare -p array
  echo ${array[0]} ${array[1]}

But this doesn't work on my vm.

I also know that I can should be able to switch the <<< syntax through backticks, $() or echo "$var" | ... but I can't get it to work - as follows:

#Fails
    IFS='=' read -ra myarray -d '' <"$var"
    echo ${array[0]} ${array[1]]}

#Fails
    echo "$var" | IFS='=' read -a array
    echo ${array[0]} ${array[1]]}

#fails
echo "a=b" | IFS='=' read -a array
declare -p array
echo ${array[0]} ${array[1]}

Grateful for any pointers as I'm really new to bash.


Solution

  • Your attempts have been confounded because you have to use the variable in the same sub-shell as read.

    $ echo 'foo=bar' | { IFS='=' read -a array; echo ${array[0]}; }
    foo
    

    And if you want your variable durable (ie, outside the sub-shell scope):

    $ var=$(echo 'foo=bar' | { IFS='=' read -a array; echo ${array[0]}; })
    $ echo $var
    foo
    

    Clearly, it isn't pretty.


    Update: If -a is missing, that suggests you're out of the land of arrays. You can try parameter substitution:

    str='foo=bar'
    var=${str%=*}
    val=${str#*=}
    

    And if that doesn't work, fall back to good ole cut:

    str='foo=bar'
    var=$(echo $str | cut -f 1 -d =)
    val=$(echo $str | cut -f 2 -d =)