[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: split a string into an array?
From: |
Kerin Millar |
Subject: |
Re: split a string into an array? |
Date: |
Fri, 11 Mar 2022 05:32:56 +0000 |
On Fri, 11 Mar 2022 14:02:40 +0900
Koichi Murase <myoga.murase@gmail.com> wrote:
> 2022年3月11日(金) 13:07 Kerin Millar <kfm@plushkava.net>:
> > You could do it this way instead:
> >
> > $ readarray -t -d $'\t' array < <(printf %s $'a\t\tb\tc')
> > $ declare -p array
> > declare -a array=([0]="a" [1]="" [2]="b" [3]="c")
> > $ readarray -t -d $'\t' array < <(printf '')
> > $ declare -p array
> > declare -a array=()
>
> There is still another corner case. The last empty element will be lost.
>
> $ readarray -t -d $'\t' array < <(printf %s $'a\t')
> $ declare -p array
> declare -a array=([0]="a")
>
> This can be solved by appending an extra separator in the input.
>
> $ sep=$'\t' input=$'a\t'
> $ mapfile -t -d "$sep" array < <(printf %s "$input${input:+$sep}")
Right. Well spotted.
>
> --
>
> I guess Peng is interested in a solution without forks. If so, we may
> use the original code by Peng but with an additional check for the
> empty input.
>
> The original code still involves pipes (or temporary files in older
> Bash or for a large input) by here strings. Instead, I usually do
> something like
>
> if [[ -o noglob ]]; then
> IFS=$sep builtin eval 'array=($input${input:+sep})'
> else
> set -f
> IFS=$sep builtin eval 'array=($input${input:+sep})'
> set +f
> fi
>
> Note: "noglob / set -f" is needed to suppress unwanted pathname
> expansions. "eval" is used to make IFS local to this command.
> "builtin" is needed to make sure that the tempenv IFS doesn't remain
> in the POSIX mode.
The problem with this is that the same word splitting behavioural issues that
would also apply to read then come into play. For instance:
$ set -f
$ sep=$'\t' input=$'foo\t\t\tbar\t'
$ IFS=$sep builtin eval 'array=($input${input:+$sep})'
$ declare -p array
declare -a array=([0]="foo" [1]="bar")
--
Kerin Millar