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