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

use*_*976 244 string shell-script

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

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t
Run Code Online (Sandbox Code Playgroud)

但它打印“lkj”,我做错了什么?

cuo*_*glm 255

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

${var::-1}
Run Code Online (Sandbox Code Playgroud)

例子:

$ a=123
$ echo "${a::-1}"
12
Run Code Online (Sandbox Code Playgroud)

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

${var: : -1}
Run Code Online (Sandbox Code Playgroud)

  • 这适用于`bash` 4.2-alpha 及更高版本,太糟糕了我可以访问的版本更早。:-/ (13认同)
  • @iamaziz:从 bash 更改日志中,`${var:offset:lenght}` 中的负长度仅在 `bash 4.2` 中添加。也许 OSX 为 `bash` 添加了自己的补丁。 (2认同)
  • @cuonglm 都不工作:/ (2认同)
  • 在 mac 上不起作用。 (2认同)

ste*_*ver 139

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

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

有关更多信息,请参阅 Bash 参考手册的 Shell 参数扩展部分:

  • @afraisse `${parameter%word}` 删除匹配 `word` 的最短后缀模式 - 请参阅 `man bash` 的参数扩展部分 (13认同)
  • 你愿意解释一下'%'背后的魔法是什么吗?? (6认同)
  • 这对 Bash 4.1.2 很有效:${t%?} 对于坚持使用 CentOS/RHEL 6.x 的人 (3认同)

小智 95

使用 sed 它应该尽可能快

sed 's/.$//'
Run Code Online (Sandbox Code Playgroud)

那么你的单一回声echo ljk | sed 's/.$//'
使用它,1 行字符串可以是任意大小。

  • 注意,一般情况下,它不会_删除字符串的最后一个字符_,而是删除字符串每一行的最后一个字符_。 (18认同)
  • `sed -z 's/.$//` 可以满足您的要求,也可以处理多行。 (2认同)

Nid*_*dal 80

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

> echo lkj | rev | cut -c (n+1)- | rev
Run Code Online (Sandbox Code Playgroud)

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

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

> lk
Run Code Online (Sandbox Code Playgroud)

来自手册rev页:

描述
rev 实用程序将指定的文件复制到标准输出,颠倒每一行中的字符顺序。如果没有指定文件,则读取标准输入。

更新:

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

$ x="lkj"
$ echo "${x%?}"
lk
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 55

一些选项取决于外壳:

  • 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具有某些实现),它还将返回非零退出状态。如果字符串包含无效字符,它也可能会产生意外结果。


Rus*_*uss 46

最便携、最短的答案几乎肯定是:

${t%?}

这适用于 bash、sh、ash、dash、busybox/ash、zsh、ksh 等。

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

请参阅此处的“删除最小后缀模式”以获取(更)更详细的解释和更多背景信息。另请参阅man bash“参数扩展”下的shell 文档(例如:)。


作为旁注,如果您想删除第一个字符,您可以使用${t#?}, 因为#匹配是从字符串的前面(前缀)而不是后面(后缀)开始的。

另外值得注意的是,%and 和#have%%##versions,它们匹配给定模式的最长版本而不是最短版本。但是,在这种情况下,两者${t%%?}${t##?}都将与它们的单个运算符执行相同的操作(因此不要添加无用的额外字符)。这是因为给定的?模式只匹配单个字符。将 a*与一些非通配符混合在一起%%,使用和会使事情变得更有趣##

理解参数扩展,或者至少知道它们的存在并知道如何查找它们,对于编写和破译多种风格的 shell 脚本非常有用。参数扩展对许多人来说通常看起来像神秘的外壳巫毒教,因为......好吧......它们神秘的外壳巫毒教(尽管如果你知道寻找“参数扩展”,则有很好的记录)。不过,当您被困在外壳中时,将其放在工具带中绝对是件好事。


Áng*_*gel 18

t=lkj
echo ${t:0:${#t}-1}
Run Code Online (Sandbox Code Playgroud)

你得到一个从 0 到字符串长度 -1 的子字符串。但是请注意,此减法是特定于 bash 的,不适用于其他 shell。

例如,dash甚至无法解析

echo ${t:0:$(expr ${#t} - 1)}
Run Code Online (Sandbox Code Playgroud)

例如,在 Ubuntu 上,/bin/shdash


小智 17

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

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin
Run Code Online (Sandbox Code Playgroud)

但不幸的是,有些版本head不包括领先的-选项。这是headOS X 附带的情况。


小智 7

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

SRC_IP_MSG=${SRC_IP_MSG%??}
Run Code Online (Sandbox Code Playgroud)


unx*_*nut 6

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

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"
Run Code Online (Sandbox Code Playgroud)


小智 5

只是为了完成纯 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/%\ /}'"
Run Code Online (Sandbox Code Playgroud)

第一个语法从字符串中获取一个子字符串,语法是 对于第二个,请注意符号,这意味着“从行尾”,语法是
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

这是上面提到的两种较短的形式

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Run Code Online (Sandbox Code Playgroud)

这里再次注意%符号,意思是 'Remove (即,替换为 '' )最短匹配模式(这里由PARAMETER末尾的转义空格'\ '表示- 这里命名为STR