如何从Bash中的字符串中删除最后n个字符?


202

var在Bash脚本中有一个包含字符串的变量,例如:

echo $var
"some string.rtf"

我想删除此字符串的最后4个字符,并将结果分配给新变量var2,这样

echo $var2
"some string"

我怎样才能做到这一点?


Answers:


15

首先,您应该明确想要的内容。如果您知道该字符串结尾.rtf并且想要删除该字符串.rtf,则可以使用var2=${var%.rtf}。如果您不知道后缀是什么,但您想要从最后一个开始删除所有内容.,可以使用var2=${var%.*}。如果您只想使所有内容保持第一.,则可以使用var2=${var%%.*}。如果只有一个期间,则后两个选项具有相同的结果,但是如果可能有多个,则应该决定要哪个。

如果您确实要始终删除确切数目的字符,则可以使用以下选项。

您是专门指定bash的,所以我们将从bash内置函数开始。工作时间最长的是我上面使用的相同的后缀删除语法:要删除四个字符,请使用var2=${var%????}。您需要为每个字符删除一个问号,因此对于较大的子字符串长度,这变得很麻烦。

较新的是子字符串提取:var2=${var::${#var}-4}。您可以在此处用任意数字代替4来删除不同数量的字符。(${#var}替换为字符串的长度,因此实际上要求保留前(长度-4)个字符。)

较新的bash版本(特别是4+,这意味着MacOS附带的版本将无法使用)可以简化为just var2=${var::-4}

如果您实际上不是在使用bash,而是在使用其他POSIX类型的shell,那么即使在普通的旧破折号中(其余都不起作用),删除后缀仍然可以使用。在zsh中,它们都可以工作,但是您必须0在冒号之间加一个:var2=${var:0:-4}等。在ksh中,您需要0,还必须使用显式的length-4表达式:var2=${var:0:${#var}-4}

当然,您可以在实用程序的帮助下使用命令替换来完成此操作。有很多可以使用的方法,但var2=$(cut -c -4 <<<"$var")可能是最短的选择。


240

您可以这样:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
我认为bash 4+。
Etan Reisner 2014年

69
它是bash4+,但是在早期版本中,您可以使用稍长的时间${v::${#v}-4}
chepner 2014年

8
bash对我没有帮助,bash说“替换不好”
Ivan Marjanovic

15
出于某种原因,在zsh中出现了${v::-4}“ zsh:预期中的大括号”。但是@fredtantini在下面的答案${v:0:-4}很好用。
Pierre D

6
错误:-2:子字符串表达式<0
爱德华(Edward)

172

要从字符串末尾删除四个字符,请使用${var%????}

最终.使用后要去除所有东西${var%.*}


12
纯shell的答案,并将在许多由于许可问题而拒绝实施BASH 4.x的系统中发现的BASH 3.x中起作用。
David W.

1
这很酷,因为它可以防止字符串变短。索引偏移变量将失败。
拉斐尔

在bash 3.2.25中工作-最好的答案-正是我在寻找的东西
capser 17-10-25

极好的答案。除去字符串前面的怎么样?
user2023370

3
@ user2023370查阅文档应显示有相应的参数替换${var#????}
Tripleee

48

对我有用的是:

echo "hello world" | rev | cut -c5- | rev
# hello w

但是我用它来修剪文件中的行,所以这看起来很尴尬。真正的用途是:

cat somefile | rev | cut -c5- | rev

cut只能使您从某个起始位置开始进行修整,如果您需要可变长度的行,那么这是不好的。因此,此解决方案反转(rev)字符串,现在我们将其与字符串的结束位置相关联,然后cut按上述方式使用,并将其再次反转(再次rev)回到其原始顺序。


这是不正确的,也不是所要求的答案。rev反转行,而不是字符串。echo $SOME_VAR | rev | ...可能不会表现出人们的期望。
Mohammad Nasirifar

2
@Mohammad由于引用不完整,因此只有一行。
Tripleee'7

38

使用变量扩展/子字符串替换

$ {var /%Pattern / Replacement}

如果var的后缀与Pattern匹配,则将Replacement替换为Pattern。

因此,您可以执行以下操作:

~$ echo ${var/%????/}
some string

或者,

如果您始终具有相同的4个字母

~$ echo ${var/.rtf/}
some string

如果它总是以结尾.xyz

~$ echo ${var%.*}
some string

您还可以使用字符串的长度:

~$ len=${#var}
~$ echo ${var::len-4}
some string

或简单地 echo ${var::-4}


len=${#var}; echo ${var::len-4}可以简化为echo ${var:0:-4}:-)编辑:或正如@iyonizer所指出的,只是echo ${var::-4}...
anishsane 2014年

26

您可以使用sed,

sed 's/.\{4\}$//' <<< "$var"

例:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string

1
以及如何将结果分配给var2
becko 2014年

这很好,因为它可以像这样在一行上工作。sed's /。\ {4 \} $ //'。无需使用变量即可使用
山姆


1

希望以下示例对您有所帮助,

echo ${name:0:$((${#name}-10))} -> ${name:start:len}

  • 在上面的命令中,name是变量。
  • start 是字符串的起点
  • len 是必须删除的字符串的长度。

例:

    read -p "Enter:" name
    echo ${name:0:$((${#name}-10))}

输出:

    Enter:Siddharth Murugan
    Siddhar

注意:Bash 4.2添加了对负子字符串的支持


这比Etan Reisner的答案中的Bourne兼容简单模式替换更为冗长。
三人房

0

通过计算字符串的大小,这对我有用。
您很容易需要回显需要返回的值,然后将其存储如下

removechars(){
        var="some string.rtf"
        size=${#var}
        echo ${var:0:size-4}  
    }
    removechars
    var2=$?

一些弦


0

在这种情况下,您可以使用基本名称,前提是您要删除的文件具有相同的后缀。

例:

basename -s .rtf "some string.rtf"

这将返回“一些字符串”

如果您不知道后缀,并希望其删除最后一个点之后(包括最后一个点)的所有内容,请执行以下操作:

f=file.whateverthisis
basename "${f%.*}"

输出“文件”

%表示印章。是您要斩波的内容,*是通配符

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.