简体   繁体   English

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

[英]How to remove last n characters from a string in Bash?

I have a variable var in a Bash script holding a string:我在 Bash 脚本中有一个变量var ,其中包含一个字符串:

echo $var
"some string.rtf"

I want to remove the last four characters of this string and assign the result to a new variable var2 , so that我想删除这个字符串的最后四个字符并将结果分配给一个新变量var2 ,这样

echo $var2
"some string"

How can I do this?我怎样才能做到这一点?

You can do like this:你可以这样做:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

To remove four characters from the end of the string use ${var%????} .要从字符串末尾删除四个字符,请使用${var%????}

To remove everything after the final .最后删除所有内容. use ${var%.*} .使用${var%.*}

First, it's usually better to be explicit about your intent.首先,通常最好明确说明您的意图。 So if you know the string ends in .rtf , and you want to remove that .rtf , you can just use var2=${var%.rtf} .因此,如果您知道字符串以.rtf结尾,并且您想删除该.rtf ,则可以使用var2=${var%.rtf} One potentially-useful aspect of this approach is that if the string doesn't end in .rtf , it is not changed at all;这种方法的一个潜在有用的方面是,如果字符串.rtf结尾,则它根本不会改变; var2 will contain an unmodified copy of var . var2将包含var的未修改副本。

If you want to remove a filename suffix but don't know or care exactly what it is, you can use var2=${var%.*} to remove everything starting with the last .如果您想删除文件名后缀但不知道或不关心它到底是什么,您可以使用var2=${var%.*}删除以最后一个. . . Or, if you only want to keep everything up to but not including the first .或者,如果您只想保留所有内容但不包括第一个. , you can use var2=${var%%.*} . ,您可以使用var2=${var%%.*} Those options have the same result if there's only one .如果只有一个. , but if there might be more than one, you get to pick which end of the string to work from. ,但如果可能有多个,您可以选择从字符串的哪一端开始工作。 On the other hand, if there's no .另一方面,如果没有. in the string at all, var2 will again be an unchanged copy of var .在字符串中, var2将再次成为var未更改副本。

If you really want to always remove a specific number of characters, here are some options.如果您真的想始终删除特定数量的字符,这里有一些选项。

You tagged this bash specifically, so we'll start with bash builtins.您专门标记了这个bash ,所以我们将从 bash 内置函数开始。 The one which has worked the longest is the same suffix-removal syntax I used above: to remove four characters, use var2=${var%????} .工作时间最长的一种是我在上面使用的相同的后缀删除语法:要删除四个字符,请使用var2=${var%????} Or to remove four characters only if the first one is a dot, use var2=${var%.???} , which is like var2=${var%.*} but only removes the suffix if the part after the dot is exactly three characters.或者仅当第一个是点时才删除四个字符,请使用var2=${var%.???} ,这类似于var2=${var%.*}但仅在点之后的部分时删除后缀正好是三个字符。 As you can see, to count characters this way, you need one question mark per unknown character removed, so this approach gets unwieldy for larger substring lengths.如您所见,要以这种方式计算字符数,您需要删除每个未知字符一个问号,因此这种方法对于较大的子字符串长度来说变得笨拙。

An option in newer shell versions is substring extraction: var2=${var:0:${#var}-4} .较新的 shell 版本中的一个选项是子字符串提取: var2=${var:0:${#var}-4} Here you can put any number in place of the 4 to remove a different number of characters.在这里,您可以用任意数字代替4以删除不同数量的字符。 The ${#var} is replaced by the length of the string, so this is actually asking to extract and keep (length - 4) characters starting with the first one (at index 0). ${#var}被字符串的长度替换,所以这实际上是要求从第一个(索引 0)开始提取和保留 (length - 4) 个字符。 With this approach, you lose the option to make the change only if the string matches a pattern;使用这种方法,只有当字符串与模式匹配时,您才无法进行更改; no matter what the actual value of the string is, the copy will include all but its last four characters.无论字符串的实际值是什么,副本都将包含除最后四个字符之外的所有字符。

You can leave the start index out;你可以不考虑开始索引; it defaults to 0, so you can shorten that to just var2=${var::${#var}-4} .它默认为 0,因此您可以将其缩短为var2=${var::${#var}-4} In fact, newer versions of bash (specifically 4+, which means the one that ships with MacOS won't work) recognize negative lengths as the index of the character to stop at, counting back from the end of the string.事实上,较新版本的 bash(特别是 4+,这意味着 MacOS 附带的那个版本将无法工作)将负长度识别为要停止的字符的索引,从字符串的末尾开始计算。 So in those versions you can get rid of the string-length expression, too: var2=${var::-4} .因此,在这些版本中,您也可以去掉字符串长度表达式: var2=${var::-4}

If you're not actually using bash but some other POSIX-type shell, the pattern-based suffix removal with % will still work – even in plain old dash, where the index-based substring extraction won't.如果您实际上不是在使用 bash,而是在使用其他一些 POSIX 类型的 shell,那么使用%的基于模式的后缀删除仍然有效 - 即使在普通的旧破折号中,基于索引的子字符串提取不会。 Ksh and zsh do both support substring extraction, but require the explicit 0 start index; Ksh 和 zsh 都支持子串提取,但需要显式的 0 起始索引; zsh also supports the negative end index, while ksh requires the length expression. zsh 也支持负端索引,而 ksh 需要长度表达式。 Note that zsh, which indexes arrays starting at 1, nonetheless indexes strings starting at 0 if you use this bash-compatible syntax .请注意,如果您使用这种与 bash 兼容的语法,则 zsh 从 1 开始索引数组,但仍然从 0 开始索引字符串 But zsh also allows you to treat scalar parameters as if they were arrays of characters, in which case the substring syntax uses a 1-based count and places the start and (inclusive) end positions in brackets separated by commas: var2=$var[1,-5] .但是 zsh 还允许您将标量参数视为字符数组,在这种情况下,子字符串语法使用基于 1 的计数并将开始和(包括)结束位置放在以逗号分隔的括号中: var2=$var[1,-5]

Instead of using built-in shell parameter expansion, you can of course run some utility program to modify the string and capture its output with command substitution.您当然可以运行一些实用程序来修改字符串并使用命令替换捕获其输出,而不是使用内置的 shell 参数扩展。 There are several commands that will work;有几个命令可以工作; one is var2=$(sed 's/.\\{4\\}$//' <<<"$var") .一个是var2=$(sed 's/.\\{4\\}$//' <<<"$var")

What worked for me was:对我有用的是:

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

But I used it to trim lines in a file so that's why it looks awkward.但我用它来修剪文件中的行,所以这就是为什么它看起来很尴尬。 The real use was:真正的用途是:

cat somefile | rev | cut -c5- | rev

cut only gets you as far as trimming from some starting position, which is bad if you need variable length rows. cut只能让您从某个起始位置进行修剪,如果您需要可变长度的行,这很糟糕。 So this solution reverses ( rev ) the string and now we relate to its ending position, then uses cut as mentioned, and reverses (again, rev ) it back to its original order.所以这个解决方案反转( rev )字符串,现在我们关联到它的结束位置,然后使用前面提到的cut ,并将它反转(再次, rev )回到它的原始顺序。

Using Variable expansion/Substring replacement :使用变量扩展/子串替换

${var/%Pattern/Replacement} ${var/%Pattern/Replacement}

If suffix of var matches Pattern, then substitute Replacement for Pattern.如果 var 的后缀匹配 Pattern,则用 Replacement 替换 Pattern。

So you can do:所以你可以这样做:

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

Alternatively,或者,

If you have always the same 4 letters如果你总是有相同的 4 个字母

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

If it's always ending in .xyz :如果它总是以.xyz结尾:

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

You can also use the length of the string:您还可以使用字符串的长度:

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

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

You could use sed,你可以使用sed,

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

EXample:例子:

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

Hope the below example will help,希望下面的例子会有所帮助,

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

  • In above command, name is the variable.在上面的命令中,name 是变量。
  • start is the string starting point start是字符串的起点
  • len is the length of string that has to be removed. len是必须删除的字符串的长度。

Example:例子:

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

Output:输出:

    Enter:Siddharth Murugan
    Siddhar

Note: Bash 4.2 added support for negative substring注意:Bash 4.2 添加了对负子字符串的支持

I tried the following and it worked for me:我尝试了以下方法,它对我有用:

#! /bin/bash

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

Output: hel输出: hel

In this case you could use basename assuming you have the same suffix on the files you want to remove.在这种情况下,您可以使用 basename 假设您要删除的文件具有相同的后缀。

Example:例子:

basename -s .rtf "some string.rtf"

This will return "some string"这将返回“一些字符串”

If you don't know the suffix, and want it to remove everything after and including the last dot:如果您不知道后缀,并希望它删除最后一个点之后的所有内容:

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

outputs "file"输出“文件”

% means chop, . % 表示砍,。 is what you are chopping, * is wildcard是你要砍的,* 是通配符

This worked for me by calculating size of string.这通过计算字符串的大小对我有用。
It is easy you need to echo the value you need to return and then store it like below很容易你需要回显你需要返回的值,然后像下面一样存储它

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

some string一些字符串

The top answer doesn't work for me, because mac os x ships with a different version of bash.最佳答案对我不起作用,因为 mac os x 附带了不同版本的 bash。

I use sed like so:我像这样使用 sed :

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

removes the last character删除最后一个字符

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

removes the last 2 characters.删除最后 2 个字符。

This also can do the job:这也可以完成这项工作:

... | 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM