删除多个可能的后缀

删除多个可能的后缀

示例:我想创建一个快速命令来缩小图像(对于我的文件浏览器)。

...
FN="/tmp/some-image.jpg"
gm convert "$FN" -resize 50% "$(dirname $FN)/$(basename $FN .jpg/png/gif).jpg"
...

如何指定应删除多个后缀?

答案1

basename只需要删除一个后缀,并给出您无论如何都不想要的基本名称(删除目录组件),因此basename并不是真正适合您需要的工具。

从字符串中提取数据的传统工具是expr

FN_without_extension=$(expr "x$FN" : 'x\(.*\)\.')

但是现代 shell(例如zshbashkshashyash、所有 POSIX 兼容的sh...)都有内置的运算符,所以现在你几乎不需要expr(最好避免它,因为它有一些问题)。

${var%pattern}

从末尾删除(最小的)部分匹配模式$var

gm convert "$FN" -resize 50% "${FN%.*}.jpg"

Shell 喜欢tcshzsh有运算符来删除扩展。兹什:

gm convert $FN -resize 50% $FN:r.jpg

r为了根名)。

如果您想删除扩展名,仅当它是 jpg/png/gif 之一时,那么事情就会变得更加复杂并且依赖于 shell。

zsh

gm convert $FN -resize 50% ${FN%.(jpg|png|gif)}.jpg

ksh

gm convert "$FN" -resize 50% "${FN%.@(jpg|png|gif)}.jpg"

bash

shopt -s extglob
gm convert "$FN" -resize 50% "${FN%.@(jpg|png|gif)}.jpg"

expr

gm convert "$FN" -resize 50% "$(
  expr \( "x$FN" : '\(.*\)\.png$' \| \
          "x$FN" : '\(.*\)\.jpg$' \| \
          "x$FN" : '\(.*\)\.gif$' \| "x$FN" \) : 'x\(.*\)')".jpg

(是的,这很复杂,这是为了解决一些问题expr)。

通过一些expr实现,它可以简化为:

expr \( "x$FN" : '\(.*\)\.\(png\|jpg\|gif\)$' \| "x$FN" \) : 'x\(.*\)'

您还可以使用sed

FN_without_ext=$(printf '%s\n' "$FN" |
  sed -e '$!b' -e 's/\.png$//;t' -e 's/\.gif$//;t' -e 's/\.jpg$//')

如果你希望不区分大小写,你可以将png/gif/jpg上面所有解决方案中的 替换为[pP][nN][gG]...,一些 shell/工具也可以进行不区分大小写的匹配:

zsh:

 setopt extendedglob
 FN_without_ext=${FN%.(#i)(gif|png|jpg)}

ksh93:

 FN_without_ext=${FN%.~(i:gif|png|jpg)}

bash:

 shopt -s nocasematch
 LC_ALL=C
 if [[ $FN =~ (.*)\.(gif|png|jpg)$ ]]; then
   FN_without_ext=${BASH_REMATCH[1]}
 else
   FN_without_ext=$FN
 fi

GNU sed

 FN_without_ext=$(printf '%s\n' "$FN" | sed -r '$s/\.(png|gif|jpg)$//I')

答案2

这应该能解决问题吗?它基本上是删除.mp3.wav扩展:

$ basename -s .wav $(basename -s .mp3 'some_file.mp3')
some_file
$ basename -s .wav $(basename -s .mp3 'some_file.wav')
some_file
$ basename -s .wav $(basename -s .mp3 'some_file.rs') 
some_file.rs

相关内容