How to find the last field using 'cut'

LinuxBashCut

Linux Problem Overview


Without using sed or awk, only cut, how do I get the last field when the number of fields are unknown or change with every line?

Linux Solutions


Solution 1 - Linux

You could try something like this:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev

Explanation

  • rev reverses "maps.google.com" to be moc.elgoog.spam
  • cut uses dot (ie '.') as the delimiter, and chooses the first field, which is moc
  • lastly, we reverse it again to get com

Solution 2 - Linux

Use a parameter expansion. This is much more efficient than any kind of external command, cut (or grep) included.

data=foo,bar,baz,qux
last=${data##*,}

See http://mywiki.wooledge.org/BashFAQ/100">BashFAQ #100 for an introduction to native string manipulation in bash.

Solution 3 - Linux

It is not possible using just cut. Here is a way using grep:

grep -o '[^,]*$'

Replace the comma for other delimiters.

Explanation:

  • -o (--only-matching) only outputs the part of the input that matches the pattern (the default is to print the entire line if it contains a match).
  • [^,] is a character class that matches any character other than a comma.
  • * matches the preceding pattern zero or more time, so [^,]* matches zero or more non‑comma characters.
  • $ matches the end of the string.
  • Putting this together, the pattern matches zero or more non-comma characters at the end of the string.
  • When there are multiple possible matches, grep prefers the one that starts earliest. So the entire last field will be matched.

Full example:

If we have a file called data.csv containing

one,two,three
foo,bar

then grep -o '[^,]*$' < data.csv will output

three
bar

Solution 4 - Linux

Without awk ?... But it's so simple with awk:

echo 'maps.google.com' | awk -F. '{print $NF}'

AWK is a way more powerful tool to have in your pocket. -F if for field separator NF is the number of fields (also stands for the index of the last)

Solution 5 - Linux

There are multiple ways. You may use this too.

echo "Your string here"| tr ' ' '\n' | tail -n1
> here

Obviously, the blank space input for tr command should be replaced with the delimiter you need.

Solution 6 - Linux

This is the only solution possible for using nothing but cut:

> echo "s.t.r.i.n.g." | cut -d'.' -f2- > [repeat_following_part_forever_or_until_out_of_memory:] | cut -d'.' -f2-

Using this solution, the number of fields can indeed be unknown and vary from time to time. However as line length must not exceed LINE_MAX characters or fields, including the new-line character, then an arbitrary number of fields can never be part as a real condition of this solution.

Yes, a very silly solution but the only one that meets the criterias I think.

Solution 7 - Linux

If your input string doesn't contain forward slashes then you can use basename and a subshell:

$ basename "$(echo 'maps.google.com' | tr '.' '/')"

This doesn't use sed or awk but it also doesn't use cut either, so I'm not quite sure if it qualifies as an answer to the question as its worded.

This doesn't work well if processing input strings that can contain forward slashes. A workaround for that situation would be to replace forward slash with some other character that you know isn't part of a valid input string. For example, the pipe (|) character is also not allowed in filenames, so this would work:

$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'

Solution 8 - Linux

the following implements A friend's suggestion

#!/bin/bash
rcut(){

  nu="$( echo $1 | cut -d"$DELIM" -f 2-  )"
  if [ "$nu" != "$1" ]
  then
    rcut "$nu"
  else
    echo "$nu"
  fi
}

$ export DELIM=.
$ rcut a.b.c.d
d

Solution 9 - Linux

An alternative using perl would be:

perl -pe 's/(.*) (.*)$/$2/' file

where you may change \t for whichever the delimiter of file is

Solution 10 - Linux

If you have a file named filelist.txt that is a list paths such as the following: c:/dir1/dir2/file1.h c:/dir1/dir2/dir3/file2.h

then you can do this: rev filelist.txt | cut -d"/" -f1 | rev

Solution 11 - Linux

Adding an approach to this old question just for the fun of it:

$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info

$ cat tmp.sh # showing off the script to do the job
#!/bin/bash
delim=';'
while read -r line; do  
    while [[ "$line" =~ "$delim" ]]; do
        line=$(cut -d"$delim" -f 2- <<<"$line")
    done
    echo "$line"
done < input.file

$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info

Besides bash, only cut is used. Well, and echo, I guess.

Solution 12 - Linux

I realized if we just ensure a trailing delimiter exists, it works. So in my case I have comma and whitespace delimiters. I add a space at the end;

$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b

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
QuestionnoobcoderView Question on Stackoverflow
Solution 1 - LinuxzedfoxusView Answer on Stackoverflow
Solution 2 - LinuxCharles DuffyView Answer on Stackoverflow
Solution 3 - LinuxtomView Answer on Stackoverflow
Solution 4 - LinuxAmir MehlerView Answer on Stackoverflow
Solution 5 - LinuxrjniView Answer on Stackoverflow
Solution 6 - LinuxA friendView Answer on Stackoverflow
Solution 7 - LinuxjstineView Answer on Stackoverflow
Solution 8 - Linuxuser2166700View Answer on Stackoverflow
Solution 9 - Linuxmoni905View Answer on Stackoverflow
Solution 10 - Linuxaperson1961View Answer on Stackoverflow
Solution 11 - LinuxKaffe MyersView Answer on Stackoverflow
Solution 12 - LinuxAnneTheAgileView Answer on Stackoverflow