0

I have successfully made a join function, which joins an array to a string using the delimeter:

function join() # Usage: string=$(join "delimeter" "${array[@]}" )
{
    local array=( "${@:2}" )
    OLD_IFS="$IFS"
    IFS="$1"
    local string="${array[*]}"
    IFS="$OLD_IFS"
    echo "$string"
}

I have also tried to make a split function which should do the opposite:

function split() # Usage: array=( $(split "delimeter" "$string") )
{
    OLD_IFS="$IFS"
    IFS="$1"
    local array=( $2 )
    IFS="$OLD_IFS"
    echo "${array[@]}"
}

But, when I use the split command and the result contains spaces, it will not work as expected. Example:

array=( "foo" "bar" "baz" "foo bar" )
string=$(join "|" "${array[@]}")
echo $string
array=( $(split "|" "$string") )
for i in ${array[@]}
do
    echo $i
done

The last element "foo bar" has been split too. I think the solution is that you have to do array=( "$(split '|' "$string")" ), but I do not know how to nest the quotes probably.

2 Answers 2

3

Note that IFS can be a local variable in a function, so you don't have to backup and restore its value:

join () { local IFS="$1"; local s="${@:2}"; printf "%s" "$s"; }

Here's an implementation of split that requires an eval:

# usage: split varName separator stringToSplit
split () {
  local var="$1"
  local IFS="$2"
  set -- $3
  echo "declare -a $var=( $(printf "\"%s\" " "$@") )"
}

Demonstration

$ a=( foo bar "hello world" baz )
$ s=$(join , "${a[@]}")
$ echo $s
foo,bar,hello world,baz
$ split b , "$s"
declare -a b=( "foo" "bar" "hello world" "baz"  )
$ eval $(split b , "$s")
$ for x in "${b[@]}"; do echo "$x"; done
foo
bar
hello world
baz
2

The problem is at the end of your split () function. You serialize array back to string! So it is again string separated by spaces, which does not recognize if the space was within the items or not. So, I know it is not very clean, but you'll have to return the value from split() function using a global variable (omit the keyword local in the example, and simplify the call, and and double quotes to the for command and some other cosmetic changes and it works...:

function split() # Usage: array=( $(split "delimeter" "$string") )
{
    OLD_IFS="$IFS"
    IFS="$1"
    array2=( $2 )
    IFS="$OLD_IFS"
}


array=( "foo" "bar" "baz" "foo bar" )
string=$(join "|" "${array[@]}")
echo $string
split "|" "$string"
for i in "${array2[@]}"
do
    echo $i
done

Don't know if there is cleaner way, to avoid the global variable, but I doubt.

Not the answer you're looking for? Browse other questions tagged or ask your own question.