How to split a string in shell and get the last field

BashSplitTokenizeCut

Bash Problem Overview


Suppose I have the string 1:2:3:4:5 and I want to get its last field (5 in this case). How do I do that using Bash? I tried cut, but I don't know how to specify the last field with -f.

Bash Solutions


Solution 1 - Bash

You can use http://www.linuxjournal.com/article/8919">string operators:

$ foo=1:2:3:4:5
$ echo ${foo##*:}
5

This trims everything from the front until a ':', greedily.

${foo  <-- from variable foo
  ##   <-- greedy front trim
  *    <-- matches anything
  :    <-- until the last ':'
 }

Solution 2 - Bash

Another way is to reverse before and after cut:

$ echo ab:cd:ef | rev | cut -d: -f1 | rev
ef

This makes it very easy to get the last but one field, or any range of fields numbered from the end.

Solution 3 - Bash

It's difficult to get the last field using cut, but here are some solutions in awk and perl

echo 1:2:3:4:5 | awk -F: '{print $NF}'
echo 1:2:3:4:5 | perl -F: -wane 'print $F[-1]'

Solution 4 - Bash

Assuming fairly simple usage (no escaping of the delimiter, for example), you can use grep:

$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5

Breakdown - find all the characters not the delimiter ([^:]) at the end of the line ($). -o only prints the matching part.

Solution 5 - Bash

You could try something like this if you want to use cut:

echo "1:2:3:4:5" | cut -d ":" -f5

You can also use grep try like this :

echo " 1:2:3:4:5" | grep -o '[^:]*$'

Solution 6 - Bash

One way:

var1="1:2:3:4:5"
var2=${var1##*:}

Another, using an array:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
var2=${var2[@]: -1}

Yet another with an array:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
count=${#var2[@]}
var2=${var2[$count-1]}

Using Bash (version >= 3.2) regular expressions:

var1="1:2:3:4:5"
[[ $var1 =~ :([^:]*)$ ]]
var2=${BASH_REMATCH[1]}

Solution 7 - Bash

$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

Simply translate the delimiter into a newline and choose the last entry with tail -1.

Solution 8 - Bash

Using sed:

$ echo '1:2:3:4:5' | sed 's/.*://' # => 5

$ echo '' | sed 's/.*://' # => (empty)

$ echo ':' | sed 's/.*://' # => (empty)
$ echo ':b' | sed 's/.*://' # => b
$ echo '::c' | sed 's/.*://' # => c

$ echo 'a' | sed 's/.*://' # => a
$ echo 'a:' | sed 's/.*://' # => (empty)
$ echo 'a:b' | sed 's/.*://' # => b
$ echo 'a::c' | sed 's/.*://' # => c

Solution 9 - Bash

There are many good answers here, but still I want to share this one using basename :

 basename $(echo "a:b:c:d:e" | tr ':' '/')

However it will fail if there are already some '/' in your string. If slash / is your delimiter then you just have to (and should) use basename.

It's not the best answer but it just shows how you can be creative using bash commands.

Solution 10 - Bash

If your last field is a single character, you could do this:

a="1:2:3:4:5"

echo ${a: -1}
echo ${a:(-1)}

Check string manipulation in bash.

Solution 11 - Bash

Using Bash.

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0

Solution 12 - Bash

echo "a:b:c:d:e"|xargs -d : -n1|tail -1

First use xargs split it using ":",-n1 means every line only have one part.Then,pring the last part.

Solution 13 - Bash

A solution using the read builtin:

IFS=':' read -a fields <<< "1:2:3:4:5"
echo "${fields[4]}"

Or, to make it more generic:

echo "${fields[-1]}" # prints the last item

Solution 14 - Bash

for x in `echo $str | tr ";" "\n"`; do echo $x; done

Solution 15 - Bash

For those that comfortable with Python, https://github.com/Russell91/pythonpy is a nice choice to solve this problem.

$ echo "a:b:c:d:e" | py -x 'x.split(":")[-1]'

From the pythonpy help: -x treat each row of stdin as x.

With that tool, it is easy to write python code that gets applied to the input.

Edit (Dec 2020): Pythonpy is no longer online. Here is an alternative:

$ echo "a:b:c:d:e" | python -c 'import sys; sys.stdout.write(sys.stdin.read().split(":")[-1])'

it contains more boilerplate code (i.e. sys.stdout.read/write) but requires only std libraries from python.

Solution 16 - Bash

Regex matching in sed is greedy (always goes to the last occurrence), which you can use to your advantage here:

$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5

Solution 17 - Bash

If you like python and have an option to install a package, you can use this python utility.

# install pythonp
pythonp -m pip install pythonp

echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questioncd1View Question on Stackoverflow
Solution 1 - BashStephenView Answer on Stackoverflow
Solution 2 - Basha3nmView Answer on Stackoverflow
Solution 3 - BashWilliam PursellView Answer on Stackoverflow
Solution 4 - BashNicholas M T ElliottView Answer on Stackoverflow
Solution 5 - BashAbdallah_98View Answer on Stackoverflow
Solution 6 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 7 - Bashuser3133260View Answer on Stackoverflow
Solution 8 - BashRafaelView Answer on Stackoverflow
Solution 9 - Bash021View Answer on Stackoverflow
Solution 10 - BashAb IratoView Answer on Stackoverflow
Solution 11 - Bashghostdog74View Answer on Stackoverflow
Solution 12 - BashCrytisView Answer on Stackoverflow
Solution 13 - BashbazView Answer on Stackoverflow
Solution 14 - BashNahid AkbarView Answer on Stackoverflow
Solution 15 - BashChristoph BöddekerView Answer on Stackoverflow
Solution 16 - BashslushyView Answer on Stackoverflow
Solution 17 - BashbombsView Answer on Stackoverflow