使用Shell脚本中的字符串操作删除字符串的最后一个字符


187

我想删除字符串的最后一个字符,我尝试了这个小脚本:

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

但它显示“ lkj”,我在做什么错?

Answers:


115

在POSIX Shell中,语法${t:-2}含义有所不同-它扩展为tif tset 的值和非null,否则扩展为value 2。要通过参数扩展修剪单个字符,您可能需要的语法是${t%?}

请注意,在ksh93bashzsh${t:(-2)}${t: -2}(注意空格)合法的,因为一个子扩张,但也有可能不是你想要的,因为他们回到开始的位置2个字符中的端部(子串即它消除了第一个字符i的字符串ijk)。

有关更多信息,请参见《 Bash参考手册》的“ Shell参数扩展”部分:


4
您是否愿意解释'%'背后的魔力是什么??
afraisse 2016年

8
@afraisse ${parameter%word}删除最短的后缀模式匹配word-请参阅man bash
steeldriver '16

3
这对于Bash 4.1.2来说效果很好:$ {t%?}对于受CentOS / RHEL 6.x困扰的人们
Joey T

185

使用bash4.2及更高版本,您可以执行以下操作:

${var::-1}

例:

$ a=123
$ echo "${a::-1}"
12

请注意,对于较旧的版本bash(例如,bash 3.2.5在OS X上),应在冒号之间和之后留空格:

${var: : -1}

13
这适用于bash4.2-alpha及更高版本,很糟糕,我可以访问的版本更早。:-/
hjk 2014年

2
@iamaziz:从bash更新日志中,${var:offset:lenght}仅在中添加了负长度bash 4.2。也许OSX添加了自己的补丁bash
cuonglm

1
@cuonglm均不起作用:/
iamaziz '16

1
在Mac上不起作用。
shinzou

1
MACsters,请低头看Russ的答案
P i

67

用于n从不使用sedOR 的行中删除最后一个字符awk

> echo lkj | rev | cut -c (n+1)- | rev

因此,例如,您可以one character使用以下命令删除最后一个字符:

> echo lkj | rev | cut -c 2- | rev

> lk

rev联机帮助页:

说明
rev实用程序将指定的文件复制到标准输出,以反转每一行中的字符顺序。如果未指定文件,则读取标准输入。

更新:

如果您不知道字符串的长度,请尝试:

$ x="lkj"
$ echo "${x%?}"
lk

61

使用sed的速度应与

sed 's/.$//'

这样,您的唯一回声就是echo ljk | sed 's/.$//'
使用此选项,一线字符串可以是任意大小。


10
请注意,在一般情况下,它不会删除字符串的最后一个字符,而是删除字符串的每一行的最后一个字符。
斯特凡Chazelas

44

一些取决于外壳的选项:

  • POSIX: t=${t%?}
  • 伯恩: t=`expr " $t" : ' \(.*\).'`
  • zsh / yash: t=${t[1,-2]}
  • bash / zsh: t=${t:0:-1}
  • ksh93 / bash / zsh / mksh: t=${t:0:${#t}-1}
  • ksh93 / bash / zsh / mksh: t=${t/%?}
  • ksh93: t=${t/~(E).$/}
  • es: @ {t=$1} ~~ $t *?

请注意,尽管所有人都应该剥离最后一个字符,但是您会发现某些实现(不支持多字节字符的实现)会剥离最后一个字节(因此如果最后一个字符是多字节的,则可能会破坏最后一个字符) )。

expr变体假定$t不以多个换行符结尾。如果结果字符串最终被使用0000或什至-0使用某些实现),它还将返回非零退出状态。如果字符串包含无效字符,也可能会产生意外结果。


尼斯和彻底!但是...我想所有这些shell都支持POSIX,所以每个人都应该使用那个外壳来实现最大的可移植性。字符数最少!
罗斯,2013年

@Russ,t=${t%?}不是Bourne,但如今您不太可能遇到Bourne的外壳。${t%?}确实可以在其他所有设备上工作。
斯特凡Chazelas

没有提供鱼壳选项!这些天可能比ksh93更受欢迎...
rien333 '17

@ rien333。我将等待接口稳定下来。fish正在进行中。在进行string问答时,尚未发布引入内建函数的2.3.0 。使用我正在测试的版本,您需要string replace -r '(?s).\z' '' -- $t(并且我希望他们希望对此进行更改,他们应该更改传递给PCRE的标志)或更复杂的标志。它也无法很好地处理换行符,而且我知道他们也计划对此进行更改。
斯特凡Chazelas

赞成POSIX答案。确认正在开发Bash 3.2.57(1)
Avindra Goolcharan'Aug

26

几乎可以肯定,最便携,最短的答案是:

${t%?}

这适用于bash,sh,ash,破折号,busybox / ash,zsh,ksh等。

它通过使用老式的shell参数扩展来工作。特别是,%指定删除t与glob模式匹配的参数的最小匹配后缀?(即:任何字符)。

有关(更多)更详细的说明和更多背景,请参见此处的 “删除最小后缀模式” 。另请参阅man bash“参数扩展”下针对您的Shell的文档(例如:)。


附带说明一下,如果要删除第一个字符,则应使用${t#?},因为#匹配项是从字符串的开头(前缀)而不是后面的(后缀)匹配。

还要注意的是,%#都有%%##版本,它们匹配给定模式的最长版本而不是最短版本。双方${t%%?}${t##?}会做同样在这种情况下,他们的单人操作,但(所以不要添加无用多余的字符)。这是因为给定的?模式仅匹配单个字符。混合在*一些非通配符和事情变得更有趣%%##

了解参数扩展,或者至少了解它们的存在并知道如何查找它们,对于编写和解密多种形式的Shell脚本非常有用。对于许多人来说,参数扩展通常看起来像奥术外壳的伏都教,因为……好吧……它们奥术外壳的伏教(尽管如果您知道要寻找“参数扩展”,也有很好的记录)。但是,当您卡在壳中时,绝对可以将它放在工具带中。


简短有趣,可在MacOS和Linux上使用!
dbernard

18
t=lkj
echo ${t:0:${#t}-1}

您会得到一个从0到字符串长度-1的子字符串。但是请注意,此减法是bash特定的,在其他shell上无效。

例如,dash甚至无法解析

echo ${t:0:$(expr ${#t} - 1)}

例如,在Ubuntu,/bin/shdash


15

您还可以使用head打印出最后一个字符以外的所有字符。

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

但不幸的是,某些版本head不包含领先-选项。这是headOS X随附的情况。


5

使用正则表达式很容易做到:

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"

5

一些改进。要删除多个字符,可以添加多个问号。例如,要从变量:中删除最后两个字符$SRC_IP_MSG,可以使用:

SRC_IP_MSG=${SRC_IP_MSG%??}

4

只是为了完成纯bash的一些可能用法:

#!/bin/bash

# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"

第一种语法从字符串中获取子字符串,语法为 :第二种语法,请注意符号,表示“从行尾”,语法为
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

这是上述两种较短的形式

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

在这里再次注意%符号,意思是“删除(也就是用”代替)最短的匹配模式(此处是从PARAMETER的末尾开始的转义空格“ \”表示,这里称为STR)


1

因为我们也可以在命令行或shell脚本中使用php。有时对于手术分析很有用。

php -r "echo substr('Hello', 0, -1);" 
// Output hell

带管道:

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell

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.