Home > OS >  Parameter Expansion instead of cut
Parameter Expansion instead of cut

Time:04-13

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
  • Related