Split string by delimiter and get N-th element
Use cut
with _
as the field delimiter and get desired fields:
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
You can also use echo
and pipe instead of Here string:
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Example:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
Beware that if $s
contains newline characters, that will return a multiline string that contains the 2nd/4th field in each line of $s
, not the 2nd/4th field in $s
.
Wanted to see an awk
answer, so here's one:
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
Using only POSIX sh constructs, you can use parameter substitution constructs to parse one delimiter at a time. Note that this code assumes that there is the requisite number of fields, otherwise the last field is repeated.
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
Alternatively, you can use an unquoted parameter substitution with wildcard expansion disabled and IFS
set to the delimiter character (this only works if the delimiter is a single non-whitespace character or if any whitespace sequence is a delimiter).
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
This clobbers the positional parameters. If you do this in a function, only the function's positional parameters are affected.
Yet another approach for strings that don't contain newline characters is to use the read
builtin.
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF