How to split a string in shell and get the last field
Matthew Barrera
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.
17 Answers
You can use string operators:
$ foo=1:2:3:4:5
$ echo ${foo##*:}
5This trims everything from the front until a ':', greedily.
${foo <-- from variable foo ## <-- greedy front trim * <-- matches anything : <-- until the last ':' } 8 Another way is to reverse before and after cut:
$ echo ab:cd:ef | rev | cut -d: -f1 | rev
efThis makes it very easy to get the last but one field, or any range of fields numbered from the end.
11It'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]' 4 Assuming fairly simple usage (no escaping of the delimiter, for example), you can use grep:
$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5Breakdown - find all the characters not the delimiter ([^:]) at the end of the line ($). -o only prints the matching part.
1You could try something like this if you want to use cut:
echo "1:2:3:4:5" | cut -d ":" -f5You can also use grep try like this :
echo " 1:2:3:4:5" | grep -o '[^:]*$' 1 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]} 0 $ echo "a b c d e" | tr ' ' '\n' | tail -1
eSimply translate the delimiter into a newline and choose the last entry with tail -1.
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 1 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.
2There 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.
Using Bash.
$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo \$${#}
0 1 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 echo "a:b:c:d:e"|xargs -d : -n1|tail -1First use xargs split it using ":",-n1 means every line only have one part.Then,pring the last part.
0A 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 for x in `echo $str | tr ";" "\n"`; do echo $x; done 1 improving from @mateusz-piotrowski and @user3133260 answer,
echo "a:b:c:d::e:: ::" | tr ':' ' ' | xargs | tr ' ' '\n' | tail -1first, tr ':' ' ' -> replace ':' with whitespace
then, trim with xargs
after that, tr ' ' '\n' -> replace remained whitespace to newline
lastly, tail -1 -> get the last string
6For those that comfortable with Python, 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. ) but requires only std libraries from python.