如何使用“剪切”查找最后一个字段


310

使用sed使用awk,当字段数未知或每行更改时,如何获取最后一个字段? cut


8
您是否爱上了cut命令:)?为什么没有其他Linux命令?
Jayesh Bhoi 2014年

7
没有sedawkperl -pe 's/^.+\s+([^\s]+)$/$1/'
jordanm 2014年


4
@MestreLion很多时候,人们阅读问题以找到解决问题的方法。这是从错误的前提开始的,该前提cut支持不支持的内容。但是我认为它很有用,因为它迫使读者考虑更容易理解的代码。我想要一个快速,简单的方法来使用cut,而无需使用多个语法为awkgrepsedrev事情的伎俩; 非常优雅,这是我从未考虑过的(即使在其他情况下笨拙)。我也喜欢从其他答案中阅读其他方法。
Beejor

3
这是一个现实生活中的问题:我想在源代码树中找到所有不同的文件扩展名,以更新.gitattributes文件。find | cut -d. -f<last>自然倾向也是如此
studog

Answers:


679

您可以尝试这样的事情:

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

说明

  • rev 将“ maps.google.com”反转为 moc.elgoog.spam
  • cut 使用点(即“。”)作为定界符,并选择第一个字段,即 moc
  • 最后,我们再次反转以获得 com

6
它不仅使用cut,但它没有sedawk。所以什么OP觉得呢?
Jayesh Bhoi 2014年

7
在过去的几个小时中,@ tom OP不仅问了更多问题。根据与OP的交互,我们知道awk / sed / etc。不允许在他的家庭作业中使用,但尚未提及rev。因此值得一

4
@zfus,我明白了。之后可能要再贴上rev
汤姆2014年

17
双重rev伟大的理想!
福特郭

6
很棒,简单,完美,也感谢您的解释-没有足够的人解释管道命令的长链中的每个步骤
Pete

128

使用参数扩展。这比任何种类的外部命令的,更有效的cut(或grep)包括在内。

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

有关bash中本机字符串操作的介绍,请参见BashFAQ#100


3
@ErwinWessels:因为bash真的很慢。使用bash运行管道,而不是批量处理数据。我的意思是,如果您在shell变量中已经有一行文本,或者您想while IFS= read -ra array_var; do :;done <(cmd)处理几行,那么这很好。但是对于大文件,rev | cut | rev可能更快!(当然,awk的速度会更快。)
彼得·科德斯

2
@PeterCordes,对于大文件,awk肯定会更快,但是要克服恒定因素的启动成本,它需要花费大量的输入。(还存在一些shell,例如ksh93,其性能接近awk,此答案中给出的语法仍然有效; bash异常缓慢,但它甚至与可用的唯一选项都不接近)。
查尔斯·达菲,2015年

1
谢谢@PeterCordes; 像往常一样,我猜每种工具都有其用例。
Erwin Wessels,2015年

1
到目前为止,这是在bash脚本中修剪单个变量的最快,最简洁的方法(假设您已经在使用bash脚本)。无需外部调用任何东西。
肯·夏普

1
@Balmipour,......然而,rev 特定于任何操作系统您正在使用提供它-它不是在所有的UNIX系统标准化。有关命令和实用程序的POSIX部分,请参见列出章节 -它不存在。而且${var##prefix_pattern}不是在bash特有的事实; 它在POSIX sh标准中,请参见2.6.2节(链接)的末尾,因此与不同rev,它始终可在任何兼容的Shell上使用。
查尔斯·达菲

89

不能使用just cut。这是一种使用方法grep

grep -o '[^,]*$'

用逗号分隔其他定界符。


3
相反,找到除最后一个字段以外的所有内容,请执行以下操作:grep -o '^.*,'
Ariel

2
这特别有用,因为rev在我的案例中添加了问题多字节unicode字符。
布莱斯

3
我试图在MinGW上执行此操作,但我的grep版本不支持-o,因此我使用了sed 's/^.*,//'它将空字符替换为最后一个逗号(包括最后一个逗号)的所有字符。
TamaMcGlinn

46

没有awk吗?...但是使用awk是如此简单:

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

AWK是一种功能更强大的工具,可以放在口袋里。-F如果对于字段分隔符NF是字段数(也代表最后一个的索引)


2
这是通用的,并且每次都完全按预期运行。在这种情况下,cut用于实现OP的最终输出就像使用勺子“切”牛排(双关语:))。awk是牛排刀。
Hickory420 '18 -10-11

3
避免不必要地使用,echo这可能会降低使用的长文件的脚本速度awk -F. '{print $NF}' <<< 'maps.google.com'
Anil_M

14

有多种方法。您也可以使用它。

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

显然,tr命令的空格输入应替换为所需的定界符。


谢谢!在busybox sh 1.0.0中起作用的东西:)
kevinf

1
这感觉就像是对我的最简单的回答,更少的管道和更清晰的含义
joeButler

1
这不适用于整个文件,这可能是OP的意思。
阿米尔(Amir)

7

这是仅使用cut的唯一可能解决方案:

回声“字符串” | 切-d'。-f2- [repeat_following_part_forever_or_until_out_of_memory:] | 切-d'。-f2-

使用此解决方案,字段的数量确实可以是未知的,并且会不时变化。但是,由于行长不得超过LINE_MAX个字符或字段(包括换行符),因此,绝对不能将任意数量的字段作为此解决方案的实际条件。

是的,这是一个非常愚蠢的解决方案,但却是唯一符合我认为标准的解决方案。


2
真好 只要取最后一个'。关闭“字符串”,这是可行的。
马特

2
我喜欢每个人都说不可能的事,然后有人听到一个可行的答案。即使确实很傻。
Beejor

可以cut -f2-循环访问直到输出不再更改为止。
loa_in_

4

如果您的输入字符串不包含正斜杠,则可以使用basename和一个子shell:

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

这没有用sed或者awk也没有用cut,所以我不太确定它是否符合问题的答案。

如果处理可能包含正斜杠的输入字符串,这将无法正常工作。解决该问题的方法是将正斜杠替换为您知道不是有效输入字符串的一部分的其他字符。例如,|文件名中也不允许使用竖线()字符,因此可以使用:

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


0

如果您有一个名为filelist.txt的文件,该文件是诸如以下内容的列表路径:c:/dir1/dir2/file1.h c:/dir1/dir2/dir3/file2.h

那么您可以执行以下操作:rev filelist.txt | 切-d“ /” -f1 | 转速


0

为这个老问题添加一个方法只是为了好玩:

$ 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

除bash外,仅使用cut。好吧,我想是回声。


嗯,为什么不完全删除剪切而只使用bash ... x]则while read -r line; do echo ${line/*;}; done <input.file得到相同的结果。
卡菲·迈尔斯,

-1

我意识到,只要确保存在尾随定界符,它就会起作用。因此,就我而言,我有逗号和空格分隔符。我在末尾添加一个空格;

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

ans="a, b, c"产生b不满足“字段数未知或每行变化”的要求
jww
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.