如何获取外壳中字符串的最后一个字符?


125

我写了以下几行来获取字符串的最后一个字符:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

适用于abcd/

$ bash last_ch.sh abcd/
/

不适用于abcd*

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

列出了当前文件夹中的文件

Answers:


96

这就是您需要引用变量的原因之一:

echo "${str:$i:1}"

否则,bash会扩展变量,在这种情况下,会在打印出来之前进行球形调整。最好在脚本中引用参数(如果文件名匹配):

sh lash_ch.sh 'abcde*'

另请参见bash参考手册中的扩展顺序。在文件名扩展之前先扩展变量。

要获取最后一个字符,您应该仅将其-1用作索引,因为负索引从字符串末尾开始计数:

echo "${str: -1}"

冒号(:)后的空格是必需的。

没有空间,这种方法将行不通。


62
顺便说一句,负索引从右开始计数,这样"${1: -1}"就足够了。
choroba

7
您应该作为正式解决方案进行回复,而不是在此处发表评论。
宝马

仅供参考:您也可以像这样在“单线”中执行此操作echo "${str:$((${#str}-1)):1}"。这样,您还可以更改返回的尾随字符。在bash v4.1.0(1)中为我工作的内容
SaxDaddy 2015年

16
@choroba的答案:注意该死的空间!这总是让我绊倒:"${1:-1}“行不通”!
mxmlnkn

192

每@perreal,引用变量很重要,但是因为我在类似的文章中读了5次,然后才找到一种更简单的方法来处理注释中的问题...

str='abcd/'
echo "${str: -1}"

输出: /

str='abcd*'
echo "${str: -1}"

输出: *

感谢以上参与此活动的每个人;我已在整个线程中适当添加了+1!


25
注意:请注意里面的空间${std: -1},没有该空间将无法使用。我遇到了这个问题,发现它${std:~0}也可以工作(带或不带空格)。虽然不确定这是否是记录在案的行为,但我没有费心去查找它。
巴特

4
它被记录在案。man bash说:以-开头的算术表达式必须与前面的空格隔开:与“使用默认值”扩展区分开来
mighq 2014年

3
太好了,谢谢分享。BASH手册页几乎让人不知所措,我去过那里好几次了。我认为他们可以围绕Shell脚本大声笑上一门大学课程。
quickshift

3
.sh尝试将检索到的字符分配给变量时,该解决方案在脚本中不起作用。例如,declare LAST=$(echo "${str: -1}") 这将导致讨厌的红色条显示语法错误,起始于:
krb686

3
如果编辑器语法检查不喜欢该空间,请尝试${str:0-1}
ttt

36

我知道这是一个非常老的话题,但是没有人提到对我最干净的答案:

echo -n $str | tail -c 1

请注意,-n只是这样,以便回显末尾不包含换行符。


15
甚至还没有比$ {str:-1}更干净
shrewmouse

8
它更清洁,因为它不依赖bash主义,因此可以与任何Posix shell一起使用。
John Eikenberry '18

什么是最“基础”的?“ $ {str:-1}”而且...最清洁的是什么?“ $ {str:-1}” Bash是成功的工具!:-)
罗杰

对于任何试图在大文件上打印最后一个字符的人,这对我来说都是成功的:cat user / folder / file.json | tail -c 1您可以将1替换为要打印的字符数。
圣地亚哥·塞拉诺

5

使用awk脚本的另一种解决方案:

最后1个字符:

echo $str | awk '{print substr($0,length,1)}'

最后5个字符:

echo $str | awk '{print substr($0,length-5,5)}'

1
不是OP要求的,但这是我发现与文件一起使用的最佳解决方案。大多数其他方法都无法为该文件添加内容,例如: cat file | awk '{print substr($0,length,1)}'谢谢!
xmar

4

单线:

${str:${#str}-1:1}

现在:

echo "${str:${#str}-1:1}"

1
为什么要使用两对括号?此外,由于4.2,可以使用负偏移,在quickshiftin的答案如下所示:echo "${str: -1}"是够(介意之间的空间:-)。
gniourf_gniourf

两对括号用于算术运算
Eduardo Cuomo

否。请参阅手册的相关部分,您将在其中阅读:长度偏移量是算术表达式(请参见Shell Arithmetic);因此,您已经在使用Shell算术了,根本不需要任何括号。此外,如果你说的是真的,那将是更符合逻辑有一个算术扩展使用$((...))
gniourf_gniourf

@gniourf_gniourf你是对的!我现在了解您先前的问题。答案更新
爱德华多·科莫

4

到目前为止,每个答案都暗示问题中的“壳”一词等同于Bash。

这是在标准的Bourne shell中可以做到的方式:

printf $str | tail -c 1

1
echo -n如user5394399所建议,当$str包含特殊格式的字符时,可以避免出现问题。
康拉德·迈尔

所述-n开关是一个bashism。它在标准的Bourne外壳中不能用作破折号等,这就是我的回答的重点。
phep

1
这不是很严格,但是POSIX认为它是实现定义的(“如果第一个操作数是-n,或者任何一个操作数包含<backslash>字符,则结果是实现定义的”)。您的答案可以printf "%s" "$str" | ...改成:-)。
康拉德·迈耶

4

尝试:

"${str:$((${#str}-1)):1}"

例如:

someone@mypc:~$ str="A random string*"; echo "$str"
A random string*
someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
*
someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
g

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.