Bash 中的字符串裁剪

Bash 中的字符串裁剪

假设我的变量中有一个字符串,如下所示。

var="/fnxn/ngfdg/abc.ext"

我可以得到这个变量的根(删除扩展名.*)如下

echo ${var%.*}

我可以得到这个变量的尾部(删除路径*/)如下

echo ${var##*/}

但现在我必须删除路径和扩展名。我可以使用另一个变量分两步完成,如下所示。

var2=${var##*/}
var3=${var2%.*}

但单步选项(类似于下面的 zsh 语法)在 bash 中显示错误消息“错误替换”。

echo ${${var##*/}%.*}

如果我获得一个可理解的单步选项来减少代码长度并避免额外的环境变量,这将很有用。

答案1

如果您有固定分机,POSIXbasename完全支持您尝试的裁剪:

basename "$var" .ext

如果你不这样做,zsh 扩展完全支持您正在尝试的内容:

如果使用 ${...} 类型参数表达式或 $(...) 类型命令替换来代替上面的 name,则首先对其进行扩展,然后使用结果,就好像它是 name 的值一样。因此可以执行嵌套操作: ${${foo#head}%tail} 用删除的 'head' 和 'tail' 替换 $foo 的值。

所以在zsh中

echo ${${var##*/}%.*}

会做你所期望的。


如果您致力于 Bash,并且想要节省行数,则可以使用 sed:

sed -e 's/\.[^.]*$//' <<<"${var##*/}"

这只是用正则表达式替换最后一个之后的所有内容.,就像现在一样丢失前缀之后。然而,我认为这并没有比两行版本特别节省内存,而且它可能也不太容易理解。

请注意,您没有理由不能在整个过程中使用相同的变量:

var2=${var##*/}
var2=${var2%.*}

扩展发生在赋值之前,所以这是安全的。如果您担心的是一个非常长的文件名被存储两次,那么现在不会发生这种情况,但我认为这不是一个现实的问题。

相关内容