如何删除最后n个字符从一个字符串在Bash?

我有一个变量var在Bash脚本中持有一个字符串:

echo $var
"some string.rtf"

我想删除这个字符串的最后四个字符,并将结果分配给一个新变量var2,以便

echo $var2
"some string"

我该怎么做呢?

536966 次浏览

你可以用sed,

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

例子:

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

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

要删除最后.之后并包括它在内的所有内容,请使用${var%.*}

有关更多参数展开,请参阅Bash的文档

你可以这样做(在bash v4和更高版本中):

#!/bin/bash


v="some string.rtf"


v2=${v::-4}


echo "$v --> $v2"

注意:macos使用bash 3。默认为X

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

$ {var / %模式/替代}

如果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}

对我有用的是:

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

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

cat somefile | rev | cut -c5- | rev

cut只能让你从某个起始位置修剪,如果你需要可变长度的行,这是不好的。因此,这个解决方案反转(rev)字符串,现在我们关联到它的结束位置,然后使用前面提到的cut,并反转(同样是rev)它回到它原来的顺序。

我尝试了以下方法,对我很有效:

#! /bin/bash


var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}

输出:hel

这是通过计算字符串的大小为我工作 很容易,你需要回显你需要返回的值,然后像

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

一些字符串

希望下面的例子能有所帮助,

__abc0 __abc2 __abc1

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

例子:

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

输出:

    Enter:Siddharth Murugan
Siddhar

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

在这种情况下,您可以使用basename,假设您在要删除的文件上有相同的后缀。

例子:

basename -s .rtf "some string.rtf"

这将返回"some string"

如果你不知道后缀,并希望它删除后面的所有内容,包括最后一个点:

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

输出“文件”

%表示切,。你砍的是*是通配符吗

首先,明确你的意图通常会更好。因此,如果你知道字符串以.rtf结尾,并且你想删除那个.rtf,你可以只使用var2=${var%.rtf}。这种方法的一个潜在有用的方面是,如果字符串.rtf结尾,则它根本不会改变;var2将包含var的未修改副本。

如果你想删除一个文件名后缀,但不知道或不关心它到底是什么,你可以使用var2=${var%.*}删除从最后一个.开始的所有内容。或者,如果你只想保留到第一个的所有内容,但不包括.,你可以使用var2=${var%%.*}。如果只有一个.,这些选项的结果是相同的,但如果可能有多个.,你可以选择从字符串的哪一端开始工作。另一方面,如果字符串中根本没有.var2将再次成为var的不变副本。

如果你真的想总是删除特定的数量字符,这里有一些选项。

你专门标记了这个bash,所以我们将从bash内置开始。工作时间最长的是我上面使用的相同的后缀删除语法:要删除四个字符,使用var2=${var%????}。或者只在第一个字符是圆点时删除四个字符,使用var2=${var%.???},它类似于var2=${var%.*},但只在圆点后面的部分恰好是三个字符时删除后缀。如您所见,要以这种方式计数字符,您需要为每个未知字符删除一个问号,因此对于较大的子字符串长度,这种方法会变得笨拙。

在较新的shell版本中,一个选项是子字符串提取:var2=${var:0:${#var}-4}。在这里,您可以在4的位置放置任何数字,以删除不同数量的字符。${#var}被字符串的长度所取代,因此这实际上是要求提取并保留(长度- 4)从第一个字符开始的字符(在索引0处)。使用这种方法,您将失去仅在字符串匹配模式时才进行更改的选项。只要字符串至少有四个字符,无论它的实际值是什么,副本都会包括除最后四个字符以外的所有字符。

你可以去掉起始索引;它默认为0,所以你可以把它缩短为var2=${var::${#var}-4}。事实上,bash的新版本(特别是4+,这意味着MacOS附带的版本将无法工作)将负长度识别为字符的下标,从字符串的末尾开始计数。所以在这些版本中,你也可以去掉字符串长度的表达式:var2=${var::-4}。如果你保留字符串长度,但字符串短于四个字符,也会触发这个解释,因为${#var}-4是负的。例如,如果字符串有三个字符,${var:0:${#var}-4}将变成${var:0:-1},并且只删除最后一个字符。

如果你实际上没有使用bash,而是使用其他posix类型的shell,那么使用%的基于模式的后缀删除仍然可以工作——即使在普通的旧破折号中,基于索引的子字符串提取也不能工作。Ksh和zsh都支持子字符串提取,但需要显式的0开始索引;ZSH还支持负结尾索引,而KSH需要长度表达式。注意,zsh索引从1开始的数组,但索引从0 如果使用这种bash兼容语法开始的字符串。但是zsh还允许您将标量参数视为字符数组,在这种情况下,子字符串语法使用基于1的计数,并将开始和(包括)结束位置放在用逗号分隔的括号中:var2=$var[1,-5]

当然,您可以不使用内置的shell参数展开,而是运行一些实用程序来修改字符串并使用命令替换捕获其输出。有几个命令可以工作;一个是var2=$(sed 's/.\{4\}$//' <<<"$var")

这也可以做到:

... | head -c -1
-c, --bytes=[-]NUM
print the first NUM bytes of each file; with the leading '-', print all but the last NUM bytes of each file

上面的答案不适合我,因为mac os x附带了不同版本的bash。

我像这样使用sed:

var2=`echo $var2 | sed 's/.$//'`

删除最后一个字符

var2=`echo $var2 | sed 's/..$//'`

删除最后2个字符。