【发布时间】:2015-02-23 20:34:10
【问题描述】:
我在 Bash 脚本中有一个变量 var,其中包含一个字符串,例如:
echo $var
"some string.rtf"
我想删除这个字符串的最后 4 个字符并将结果分配给一个新变量var2,这样
echo $var2
"some string"
我该怎么做?
【问题讨论】:
标签: bash
我在 Bash 脚本中有一个变量 var,其中包含一个字符串,例如:
echo $var
"some string.rtf"
我想删除这个字符串的最后 4 个字符并将结果分配给一个新变量var2,这样
echo $var2
"some string"
我该怎么做?
【问题讨论】:
标签: bash
您可以这样做(在 bash v4 及更高版本中):
#!/bin/bash
v="some string.rtf"
v2=${v::-4}
echo "$v --> $v2"
注意:macos 默认使用 bash 3.x
【讨论】:
bash 4+,但在早期版本中您可以使用稍长的${v::${#v}-4}。
${v::-4} croaks "zsh: 应有右大括号"。但是@fredtantini 在${v:0:-4} 下方的回答效果很好。
要从字符串末尾删除四个字符,请使用${var%????}。
要删除包含最后一个 . 之后的所有内容,请使用 ${var%.*}。
【讨论】:
${var#????}。
首先,最好明确说明您的意图。因此,如果您知道字符串以.rtf 结尾,并且想要删除该.rtf,则可以使用var2=${var%.rtf}。这种方法的一个潜在有用的方面是,如果字符串不以.rtf结尾,它根本不会改变; var2 将包含 var 的未修改副本。
如果您想删除文件名后缀但不知道或不关心它究竟是什么,您可以使用var2=${var%.*} 删除以最后一个. 开头的所有内容。或者,如果您只想将所有内容保持在 first . 之前,但不包括 var2=${var%%.*},则可以使用 var2=${var%%.*}。如果只有一个.,这些选项具有相同的结果,但如果可能有多个,您可以选择要从字符串的哪一端开始工作。另一方面,如果字符串中根本没有.,var2 将再次成为var 的未更改副本。
如果您真的想始终删除特定 数字 个字符,这里有一些选项。
您专门标记了这个bash,所以我们将从内置bash 开始。最有效的一个是我上面使用的相同的后缀删除语法:删除四个字符,使用var2=${var%????}。或者仅在第一个是点时删除四个字符,使用var2=${var%.???},类似于var2=${var%.*},但仅在点后面的部分正好是三个字符时删除后缀。如您所见,要以这种方式计算字符,您需要删除每个未知字符一个问号,因此对于较大的子字符串长度,这种方法变得笨拙。
较新的 shell 版本中的一个选项是子字符串提取:var2=${var:0:${#var}-4}。在这里,您可以用任何数字代替 4 以删除不同数量的字符。 ${#var} 被字符串的长度替换,所以这实际上是要求提取并保留 (length - 4) 个从第一个字符开始的字符(在索引 0 处)。使用这种方法,您将失去仅当字符串与模式匹配时才进行更改的选项;无论字符串的实际值是什么,副本都将包含除最后四个字符之外的所有字符。
你可以省略起始索引;它默认为 0,因此您可以将其缩短为 var2=${var::${#var}-4}。事实上,较新版本的 bash(特别是 4+,这意味着 MacOS 附带的那个将不起作用)将负长度识别为要停止的字符的索引,从字符串的末尾开始倒数。因此,在这些版本中,您也可以摆脱字符串长度表达式:var2=${var::-4}。
如果您实际上不是在使用 bash,而是在使用其他 POSIX 类型的 shell,则使用 % 删除基于模式的后缀仍然可以工作 - 即使在普通的旧破折号中,基于索引的子字符串提取不会。 Ksh 和 zsh 都支持子串提取,但需要显式的 0 开始索引; zsh 也支持负端索引,而 ksh 需要长度表达式。请注意,zsh 索引 arrays 从 1 开始,但如果您使用此 bash 兼容语法,则索引 strings 从 0 开始。但是 zsh 还允许您将标量参数视为字符数组,在这种情况下,子字符串语法使用基于 1 的计数并将开始和(包括)结束位置放在括号中,用逗号分隔:var2=$var[1,-5].
您当然可以运行一些实用程序来修改字符串并通过命令替换捕获其输出,而不是使用内置的 shell 参数扩展。有几个命令可以工作;一个是var2=$(sed 's/.\{4\}$//' <<<"$var")。
【讨论】:
${__repo%.git} 可能会更明确,因为您确切知道要删除哪四个字符。如果字符串 没有 以 .git 结尾,这也不会删除任何内容,因此即使 __repo 的值由于某种原因不包含后缀也可以。
cut -c -4 根本不像你想的那样。它只打印字符串的第一个到第四个字符,这里就是some。您无法通过 cut 实现此目的。
【讨论】:
rev 反转行,而不是字符串。 echo $SOME_VAR | rev | ...可能不会像人们期望的那样行事。
echo "hello world" | cut -c-7 和 echo "hello world" | rev | cut -c5- | rev 产生相同的输出。
var2=$(echo $var | rev | cut -c5- | rev) 这样的东西,但是是的,从技术上讲,这个是在线工作的。如果您不想将每一行作为单独的字符串处理,则多行可能无法按预期工作。
使用Variable expansion/Substring replacement:
${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}
【讨论】:
len=${#var}; echo ${var::len-4} 可以缩短为echo ${var:0:-4} :-) 编辑:或者正如@iyonizer 指出的那样,只是echo ${var::-4} ...
你可以使用 sed,
sed 's/.\{4\}$//' <<< "$var"
示例:
$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string
【讨论】:
var2?
我尝试了以下方法,它对我有用:
#! /bin/bash
var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}
输出:hel
【讨论】:
希望以下示例对您有所帮助,
echo ${name:0:$((${#name}-10))} --> ${name:start:len}
start 是字符串的起点len 是必须删除的字符串长度。例子:
read -p "Enter:" name
echo ${name:0:$((${#name}-10))}
输出:
Enter:Siddharth Murugan
Siddhar
注意:Bash 4.2 增加了对负子字符串的支持
【讨论】:
echo "{${name:0:${#name} - 1}}" 删除最后一个字符并避免“子字符串表达式
在这种情况下,您可以使用 basename 假设您要删除的文件具有相同的后缀。
例子:
basename -s .rtf "some string.rtf"
这将返回“一些字符串”
如果您不知道后缀,并希望它删除所有内容,包括最后一个点:
f=file.whateverthisis
basename "${f%.*}"
输出“文件”
% 表示砍,.是你要砍的,*是通配符
【讨论】:
这也可以完成工作:
... | 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
【讨论】:
echo "$v" | head -c -1 导致带有 BSD 头的“头:非法字节计数 -- -1”。使用 GNU 头,(ghead),echo "$v" | ghead -c -1 会导致 "some string.rtf%";没有删除任何字符。 ghead -c -1 <<<'some string.rtf' 也不会删除任何字符。最后,确认没有恶作剧..wc -c <<<"$v"; wc -c <<<"$(ghead -c -1 <<<"$v")" 表明两者都有 16 个字节。您必须使用head/ghead -c -2。对于那些感兴趣的人,ghead --version 会生成“head (GNU coreutils) 9.0”
这通过计算字符串的大小对我有用。
很容易你需要回显你需要返回的值,然后像下面这样存储它
removechars(){
var="some string.rtf"
size=${#var}
echo ${var:0:size-4}
}
removechars
var2=$?
一些字符串
【讨论】: