How to find the last field using 'cut'

2019-01-10 00:32发布

问题:

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?

回答1:

You could try something like this:

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

Explanation

  • maps.google.com's reverse will be moc.elgoog.spam
  • cut uses dot as the delimiter and chooses the first field, which is moc
  • lastly, we reverse it again (thanks for the reminder, @tom) to get com


回答2:

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 BashFAQ #100 for an introduction to native string manipulation in bash.



回答3:

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

grep -o '[^,]*$'

Replace the comma for other delimiters.



回答4:

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)



回答5:

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.



回答6:

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.



回答7:

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


回答8:

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



回答9:

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



回答10:

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 '|' '/'


标签: linux bash cut