I have a variablefull_name=first_name:last_name
, how can I use parameter expansion to extract first_name
and last_name
?
The result of this cut
command
echo $full_name | cut -d ":" -f1
is first_name
. And the result of
echo $full_name | cut -d ":" -f2
is
last_name
.
Is there a better way to achieve this? How to split a string by :
delimiter?
CodePudding user response:
In bash, a common idiom is to do:
$ full_name=first_name:last_name
$ echo "${full_name#*:}"
last_name
$ echo "${full_name%:*}"
first_name
The ${var#word}
pattern removes word from the beggining of var
, and ${var%word}
removes word from the end. The man page describes is better than I can:
${parameter#word}
${parameter##word}
Remove matching prefix pattern. The word is expanded to produce a pattern just as in pathname expansion, and matched against the expanded value of parameter using the rules described under Pattern Matching
below. If the pattern matches the beginning of the value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the ``#'' case) or the longest
matching pattern (the ``##'' case) deleted. If parameter is @ or *, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an
array variable subscripted with @ or *, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.
${parameter%word}
${parameter%%word}
Remove matching suffix pattern. The word is expanded to produce a pattern just as in pathname expansion, and matched against the expanded value of parameter using the rules described under Pattern Matching
below. If the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the ``%'' case) or the
longest matching pattern (the ``%%'' case) deleted. If parameter is @ or *, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter
is an array variable subscripted with @ or *, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.
CodePudding user response:
I would use read
instead.
IFS=: read -r first last <<< "$full_name"
For full POSIX compatibility,
IFS=: read -r first last <<EOF
$full_name
EOF
For only two fields, there's not much difference between this and parameter expansion. But read
scales to multiple fields much better than parameter expansion:
x="1:2:3:4:5"
IFS=: read -r a b c d e <<< "$x"
vs
a=${x%%:*}
t=${x#*:}
b=${t%%:*}
t=${t#*:}
c=${t%%:*}
t=${t#*:}
d=${t%%:*}
e=${t#*:}
CodePudding user response:
You might customize the IFS (Internal Field Separator) special variable's value, for example:
$ IFS=":$IFS" bla="abc:def"; for i in $bla; do echo $i; done
abc
def
It would then be good to back up the original value and then bring it back after it's not needed anymore. Otherwise you might observe unexpected behavior :D
CodePudding user response:
William Pursell has covered parameter expansion.
For this scenario you could also use parameter substitution:
$ full_name=first_name:last_name
$ echo "${full_name//:*/}"
first_name
$ fname="${full_name//:*/}"
$ echo "${fname}"
first_name
$ echo "${full_name//*:/}"
last_name
$ lname="${full_name//*:/}"
$ echo "${lname}"
last_name