我们可以使用sed命令在linux中打印每行的最后一个单词吗?


9

假设,如果有一个包含以下几行的文件,如果它们是

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

输出必须看起来像:

66

y6y46y

y5y

y66uyuyy

46

我已经尝试了命令sed 's/.* //g'文件名和其他几个sed命令,但是它不起作用。

我能知道确切的sed命令是什么吗?


是否必须使用sed
coffeMug

Answers:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

仍然会为每个空白行打印一个空行。为了避免这种情况:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

单表达式替代:sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'
jimmij 2015年

@jimmij-如果最后一个非空白序列也是第一个序列,并且前面没有空格,则该序列号无效。另外,您最好也可以.*在尾部进行操作-排除w /之外的任何空白.*[^[:blank:]]
mikeserv



4

您快到了。只需指定最后一个字即可:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

它能做什么:

  1. '^。*'删除行首和所有空格内的所有内容。
  2. '\(...)\'匹配一个模式,并将其返回为\ 1。
  3. '[^]'匹配没有空格的任何内容。

(已编辑以添加更好的解决方案。感谢Hildred!)


1
这是一个较短的表达式:sed -r 's/.* ([^ ]+)/\1/g'如果允许扩展的正则表达式,通常是这种情况。
mkalkov

较短的版本,使用替换您不想保留的内容而不是您想要保留的内容:sed 's/.* //'
Uriel

2

您可以使用grep代替的适当模式sed,例如:

grep -o "[a-Z0-9]*$"

在此示例中,[...]包含被认为适合于“单词”的字符范围(在这种情况下为字母数字,可以添加其他符号,其中一些必须转义)。


2
假设该行的末尾没有空白。a-Z因为即使在基于ASCII的语言环境中,范围也没有多大意义。请注意,这-o是一个GNU扩展。
斯特凡Chazelas

0

如果您将单词限定为表示1个或多个非空白字符的任何序列,那么答案肯定是肯定的,而且也非常简单。这是因为[[:blank:]]*[^[:blank:]]*是布尔补数,并且-假设字符串中的所有字符都完整[[:blank:]]*-U [^[:blank:]]*可以以几乎相同的方式描述任何可能的字符串.*

如果字符串中存在不完整的字符或无效的字节序列,那么任何人都无法成功地从头到尾描述它-有时会以错误的编码解释字符串。为了确保任何字符串中每个字节的完整字符,可以强制使用C语言环境:

LC_ALL=C sed ...

...这将避免描述字符串从头部到尾部有一个包容各方的图案,如的任何问题.*([ ]*[^ ]*)*

完全互补的模式可以根据需要在任意长度上从左到右重复多次,以在最后一次可能的出现时降落而不会中断模式。无疑,这是常规语言。

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

这两个版本仍将打印空白行,这是因为Kleene *星与零个或多个图案匹配。它首先匹配零个或多个非空白字符,然后匹配零个或多个空白字符,然后匹配零个或多个出现的分组匹配,直到它完全匹配了字符串。

具有匹配的这一切,神奇发生在更换-引用返回按组\1\2各的最后出现。因此,当进行替换时,所有字符串将仅替换为零个或多个非空白字符(或子组)行中的最后一次出现\2

当然,这适用于任何可能的字符串-甚至是一个空字符串-这意味着两种形式都将为仅包含空白字符或根本不包含空格的行打印换行符。为了解决这个问题,您可以做几件事,但首先让字符类更容易键入:

b='[:blank:]'

现在,仅在一行包含一个或多个非空白字符时打印,您可以执行以下操作:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. BRE情况-始终执行替换,并且仅打印具有至少一个剩余字符的图案空间。
  2. ERE情况-仅在包含至少一个非空白char的模式空间上尝试进行替换。

只要语法正确,这两种形式都可以使用这两种方法。

-n开关禁用模式空间的自动打印,并且仅当成功时ps///指向ubstitution或/address /命令的标志才会打印其结果。

同样的逻辑也可以用于获得任何{num}出现次数,例如:

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

...其中num两个正则表达式中的都可以替换为一个数字,以仅打印{num}指定的出现的一系列非空白字符。此处使用略有不同的格式来确保计数不偏斜字符串中的前导空格。

请注意,-EERE开关sed在两个BSD和GNU版本是支持的,虽然它不是尚未 POSIX标准语法。


不错的解释,不错的技巧,但请注意,它不适用于传统的 sed实现(例如Solaris / usr / bin / sed),并且比更简单的方法(用超过25个字符长的输入行耗尽内存)要昂贵得多。在sed_su3从传家宝工具箱中的实例)。因此,尽管我喜欢答案,但我不推荐这种方法。
斯特凡Chazelas

在FreeBSD中似乎也不起作用。
斯特凡Chazelas

@StéphaneChazelas-是的,这种事情的表现确实很糟糕,但是对于选择编号事件可能非常有效。而且对于行尾情况,情况s/.* \([^[:blank:]]\{1,\}\).*/\1/要好得多,但是当涉及多行时,难度会更大。不过,'s/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]就在前几天,我发现可以有效地支持这一点。无论如何,只要逻辑上没有明显错误,我就很高兴-我只是以为我一定错过了什么。
mikeserv'2

@StéphaneChazelas-哦,关于旧的seds-有点奇怪-按照标准应该听起来不错。xrat说... 标准开发人员将常见的历史行为视为支持特定行为的"\n*""\n\{min,max\}", "\(...\)*""\(...\)\{min,max\}"
mikeserv'2

@StéphaneChazelas-标准说... 如果由于星号( '*' )或间隔表达式(参见第(5)条),后向引用引用的子表达式匹配多个字符串(请参阅第(5)条),则后向引用应匹配最后一个(最右边) )的这些字符串。我很确定我还是用w来测试的minised- minised不管怎么说,我前几天确实在测试一些奇怪的东西。
mikeserv

-1

是。以下sed命令首先删除所有结尾的空格(s/ *$//),然后删除直到最后一个空格(包括最后一个空格s/.* //)的所有内容。[[:blank:]]为了捕获制表符和其他类似空格的字符,可能值得用文字空白代替。

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

-1
cat file_name | rev | cut -f1 -d ' ' | rev
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.