【发布时间】:2011-03-10 21:29:31
【问题描述】:
假设我有字符串1:2:3:4:5,我想获取它的最后一个字段(在本例中为5)。我如何使用 Bash 做到这一点?我试过cut,但我不知道如何用-f指定最后一个字段。
【问题讨论】:
假设我有字符串1:2:3:4:5,我想获取它的最后一个字段(在本例中为5)。我如何使用 Bash 做到这一点?我试过cut,但我不知道如何用-f指定最后一个字段。
【问题讨论】:
你可以使用string operators:
$ foo=1:2:3:4:5
$ echo ${foo##*:}
5
这会贪婪地修剪从前面到 ':' 的所有内容。
${foo <-- from variable foo
## <-- greedy front trim
* <-- matches anything
: <-- until the last ':'
}
【讨论】:
1:2:3:4:5:,则以下 William 的答案 (stackoverflow.com/a/3163857/520162) 也会返回 5(使用字符串运算符时会产生空结果) .这在解析可能包含(或不包含)结束 / 字符的路径时特别方便。
${foo%:*}。 # - 从头开始; % - 从头到尾。 #, % - 最短匹配; ##, %% - 最长匹配。
echo ${pwd##*/} 不起作用。
pwd 视为变量。试试dir=$(pwd); echo ${dir##*/}。为我工作!
另一种方法是在cut前后反转:
$ echo ab:cd:ef | rev | cut -d: -f1 | rev
ef
这使得获取最后一个字段或从末尾编号的任何字段范围变得非常容易。
【讨论】:
echo "1 2 3 4" | rev | cut -d " " -f1 | rev
rev,这正是我所需要的! cut -b20- | rev | cut -b10- | rev
使用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]'
【讨论】:
/ 字符的路径:/a/b/c/d 和 /a/b/c/d/ 产生相同的结果 (d ) 处理pwd | awk -F/ '{print $NF}' 时。在/a/b/c/d/的情况下,接受的答案会导致空结果
/ 作为分隔符,如果您的路径是/my/path/dir/,它将使用最后一个分隔符之后的值,这只是一个空字符串。所以如果你需要像我一样做这样的事情,最好避免使用斜杠。
awk '{$NF=""; print $0}' FS=: OFS=: 这样的东西通常效果很好。
假设使用相当简单(例如,没有转义分隔符),您可以使用 grep:
$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5
Breakdown - 在行尾 ($) 查找除定界符 ([^:]) 之外的所有字符。 -o 只打印匹配的部分。
【讨论】:
一种方式:
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]}
【讨论】:
如果你想使用cut,你可以试试这样的:
echo "1:2:3:4:5" | cut -d ":" -f5
你也可以使用grep试试这样:
echo " 1:2:3:4:5" | grep -o '[^:]*$'
【讨论】:
$ echo "a b c d e" | tr ' ' '\n' | tail -1
e
只需将分隔符转换为换行符,然后使用tail -1 选择最后一个条目。
【讨论】:
\n,它将失败,但在大多数情况下是最易读的解决方案。
使用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
【讨论】:
【讨论】:
a 的最后一个字符,而不是最后一个字段。
这里有很多好的答案,但我还是想用 basename 分享这个:
basename $(echo "a:b:c:d:e" | tr ':' '/')
但是,如果您的字符串中已经有一些“/”,它会失败。 如果斜杠 / 是您的分隔符,那么您只需要(并且应该)使用 basename。
这不是最佳答案,但它只是展示了如何使用 bash 命令发挥创造力。
【讨论】:
使用 Bash。
$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo \$${#}
0
【讨论】:
echo ${!#} 而不是eval echo \$${#}。
echo "a:b:c:d:e"|xargs -d : -n1|tail -1
先用xargs用“:”分割,-n1表示每一行只有一个部分。然后,pring最后一部分。
【讨论】:
使用 read 内置的解决方案:
IFS=':' read -a fields <<< "1:2:3:4:5"
echo "${fields[4]}"
或者,让它更通用:
echo "${fields[-1]}" # prints the last item
【讨论】:
for x in `echo $str | tr ";" "\n"`; do echo $x; done
【讨论】:
sed 中的正则表达式匹配是贪婪的(总是到最后一次出现),您可以在这里使用它来发挥自己的优势:
$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5
【讨论】:
对于那些熟悉 Python 的人来说,https://github.com/Russell91/pythonpy 是解决这个问题的不错选择。
$ echo "a:b:c:d:e" | py -x 'x.split(":")[-1]'
来自 pythonpy 帮助:-x treat each row of stdin as x。
使用该工具,可以轻松编写应用于输入的 Python 代码。
编辑(2020 年 12 月): Pythonpy 不再在线。 这是一个替代方案:
$ echo "a:b:c:d:e" | python -c 'import sys; sys.stdout.write(sys.stdin.read().split(":")[-1])'
它包含更多样板代码(即sys.stdout.read/write),但只需要来自 python 的标准库。
【讨论】:
如果你喜欢 python 并且可以选择安装包,你可以使用this python utility。
# install pythonp
pythonp -m pip install pythonp
echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5
【讨论】:
echo "1:2:3:4:5" | python -c "import sys; print(list(sys.stdin)[0].split(':')[-1])"
pythonp 包的全部目的是让你做与 python -c 相同的事情,但字符输入更少。请查看存储库中的 README。