Pomyślnie wykonałem funkcję join, która łączy tablicę z łańcuchem za pomocą ogranicznika:

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

Próbowałem również stworzyć funkcję split, która powinna działać odwrotnie:

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

Ale kiedy używam polecenia split, a wynik zawiera spacje, nie będzie działać zgodnie z oczekiwaniami. Przykład:

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

Ostatni element „foo bar” również został podzielony. Myślę, że rozwiązaniem jest to, że musisz zrobić array=( "$(split '|' "$string")" ), ale prawdopodobnie nie wiem, jak zagnieździć cudzysłowy.

0
Tyilo 24 lipiec 2011, 02:00

2 odpowiedzi

Najlepsza odpowiedź

Zauważ, że IFS może być zmienną lokalną w funkcji, więc nie musisz tworzyć kopii zapasowej i przywracać jej wartości:

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

Oto implementacja podziału, która wymaga oceny:

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

Demonstracja

$ 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
3
glenn jackman 24 lipiec 2011, 06:53

Problem jest na końcu funkcji split (). Serializujesz tablicę z powrotem do ciągu! Jest to więc znowu łańcuch oddzielony spacjami, który nie rozpoznaje, czy spacja była w elementach, czy nie. Wiem więc, że to nie jest zbyt czyste, ale będziesz musiał zwrócić wartość z funkcji split() za pomocą zmiennej globalnej (pomiń słowo kluczowe local w przykładzie i uprość wywołanie, a podwójne cudzysłowy w poleceniu for i kilka innych kosmetycznych zmian i działa...:

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

Nie wiem, czy istnieje czystszy sposób na uniknięcie zmiennej globalnej, ale wątpię.

2
Tomas 24 lipiec 2011, 03:24