如何在shell中分割字符串并获取最后一个字段


292

假设我有字符串,1:2:3:4:5并且想要获取它的最后一个字段(5在这种情况下)。如何使用Bash做到这一点?我试过了cut,但是我不知道如何用来指定最后一个字段-f

Answers:


429

您可以使用字符串运算符

$ foo=1:2:3:4:5
$ echo ${foo##*:}
5

贪婪地修剪从前到':'的所有内容。

${foo  <-- from variable foo
  ##   <-- greedy front trim
  *    <-- matches anything
  :    <-- until the last ':'
 }

7
虽然这对于给定的问题有效,但如果字符串为,则下面William的答案(stackoverflow.com/a/3163857/520162)也将返回(使用字符串运算符时将产生空结果)。这在解析可能包含(或不包含)结束符的路径时特别方便。51:2:3:4:5:/
eckes 2013年

9
那么您将如何做相反的事情?回显“ 1:2:3:4:”?
Dobz 2014年

11
以及如何将零件保留在最后一个分隔符之前?显然是使用${foo%:*}#- 从开始; %-从头开始。#%-最短匹配;##%%-最长的比赛。
Mihai Danila 2014年

1
如果我想从路径中获取最后一个元素,应该如何使用?echo ${pwd##*/}不起作用。
Putnik

2
该命令将其pwd视为变量的@Putnik 。尝试dir=$(pwd); echo ${dir##*/}。为我工作!
Stan Strum,

344

另一种方法是在前后扭转cut

$ echo ab:cd:ef | rev | cut -d: -f1 | rev
ef

这样很容易获得最后一个字段,或者从末尾开始编号的任何范围的字段。


17
这个答案很好,因为它使用了“剪切”,作者大概已经很熟悉了。另外,我喜欢这个答案,因为使用的是“剪切”并且有这个确切的问题,因此可以通过搜索找到该线程。
2013年

6
一些使用空格作为分隔符的剪切和粘贴的饲料:echo "1 2 3 4" | rev | cut -d " " -f1 | rev
funroll

2
转速| 切-d -f1 | 转速是如此高明!谢谢!帮助了我一堆(我的用例是rev | -d''-f 2- | rev
EdgeCaseBerg 2013年

1
我总是忘记了rev,这正是我所需要的!cut -b20- | rev | cut -b10- | rev
shearn89 '17

我最终得到了这个解决方案,我尝试用“ awk -F” /“'{print $ NF}'”剪切文件路径对我来说有些中断,因为包括空格在内的文件名也被分割了
THX

76

使用cut很难获得最后一个字段,但是这里有一些awk和perl解决方案

echo 1:2:3:4:5 | awk -F: '{print $NF}'
echo 1:2:3:4:5 | perl -F: -wane 'print $F[-1]'

5
此解决方案相对于公认的答案有很大的优势:它也匹配包含或不包含结束/符的路径:/a/b/c/d并在处理时/a/b/c/d/产生相同的结果(dpwd | awk -F/ '{print $NF}'。在以下情况下,已接受的答案导致结果为空/a/b/c/d/
eckes 2013年

@eckes在AWK解决方案的情况下,在GNU bash上,版本4.3.48(1)-发行版是不正确的,因为无论是否有斜杠都很重要。简单地说,AWK将/用作定界符,如果您的路径是AWK,它将使用/my/path/dir/最后一个定界符之后的值,它只是一个空字符串。因此,如果您需要像我这样做,最好避免使用斜杠。
演讲

我将如何获得子字符串直到最后一个字段?
blackjacx

1
@blackjacx有一些怪癖,但类似的东西awk '{$NF=""; print $0}' FS=: OFS=:通常效果很好。
威廉普塞尔6:50

29

假设用法非常简单(例如,不转义分隔符),则可以使用grep:

$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5

细分-在行($)的末尾查找所有字符,而不是定界符([^:])。-o仅打印匹配的部分。


-E表示使用扩展语法;[^ ...]表示所列字符以外的任何字符;+一个或多个此类匹配项(将使用该模式的最大可能长度;该项目是gnu扩展名)-例如,分隔字符为冒号。
亚历山大·斯托尔

18

单程:

var1="1:2:3:4:5"
var2=${var1##*:}

另一个,使用数组:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
var2=${var2[@]: -1}

还有一个数组:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
count=${#var2[@]}
var2=${var2[$count-1]}

使用Bash(版本> = 3.2)正则表达式:

var1="1:2:3:4:5"
[[ $var1 =~ :([^:]*)$ ]]
var2=${BASH_REMATCH[1]}

11
$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

只需将定界符转换为换行符,然后使用选择最后一个条目tail -1


如果最后一项包含\n,它将失败,但在大多数情况下是最易读的解决方案。
Yajo 2014年

7

使用sed

$ echo '1:2:3:4:5' | sed 's/.*://' # => 5

$ echo '' | sed 's/.*://' # => (empty)

$ echo ':' | sed 's/.*://' # => (empty)
$ echo ':b' | sed 's/.*://' # => b
$ echo '::c' | sed 's/.*://' # => c

$ echo 'a' | sed 's/.*://' # => a
$ echo 'a:' | sed 's/.*://' # => (empty)
$ echo 'a:b' | sed 's/.*://' # => b
$ echo 'a::c' | sed 's/.*://' # => c

4

如果您的最后一个字段是单个字符,则可以执行以下操作:

a="1:2:3:4:5"

echo ${a: -1}
echo ${a:(-1)}

检查bash中的字符串操作


这不起作用:它给最后一个字符a,不是最后一个字段
gniourf_gniourf

1
没错,如果您知道最后一个字段的长度,那就很好了。如果不是,那么您必须使用其他东西...
Ab Irato

4

这里有很多好的答案,但是我仍然想使用basename共享这个答案:

 basename $(echo "a:b:c:d:e" | tr ':' '/')

但是,如果您的字符串中已经有一些“ /”,它将失败。如果斜杠/是您的分隔符,那么您只需要(并且应该)使用basename。

这不是最佳答案,而只是显示了如何使用bash命令发挥创造力。


2

使用Bash。

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0

本来可以echo ${!#}代替eval echo \$${#}
拉法

2
echo "a:b:c:d:e"|xargs -d : -n1|tail -1

首先使用xargs使用“:”分割它,-n1表示每一行只有一部分。然后,最后一行。




1

尽管一个简单的解决方案是反转输入字符串的顺序,但答案可能会晚一点。无论长度如何,这都将使您始终获得最后一个项目。

[chris@desktop bin]$ echo 1:2:3:4:5 | rev | cut -d: -f1
5

但是,请务必注意,如果使用此方法并且数字大于1位(或在任何情况下均大于一个字符),则将需要在管道输出上运行另一个“ rev”命令。

[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1
42
[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1 | rev
24

希望我能帮上忙


1

使用内置读取方法的解决方案:

IFS=':' read -a fields <<< "1:2:3:4:5"
echo "${fields[4]}"

或者,使其更通用:

echo "${fields[-1]}" # prints the last item

0

如果您喜欢python并可以选择安装软件包,则可以使用此python实用工具

# install pythonp
pythonp -m pip install pythonp

echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5

python可以直接执行此操作: echo "1:2:3:4:5" | python -c "import sys; print(list(sys.stdin)[0].split(':')[-1])"
MortenB

@MortenB你误会了。pythonp打包的全部目的是使您做的事python -c与减少字符键入次数相同。请查看存储库中的自述文件。
炸弹

0

正则表达式匹配 sed是贪婪的(总是到最后一次出现),您可以在这里利用它来发挥自己的优势:

$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5
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.