web-dev-qa-db-ja.com

複数の可能なサフィックスを削除する

例:(ファイルブラウザ用に)画像を縮小するクイックコマンドを作成したいと思います。

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

複数のサフィックスを削除するように指定するにはどうすればよいですか?

3
Profpatsch

basenameは、削除するサフィックスを1つだけ取得し、必要のないベース名(ディレクトリコンポーネントを削除)を指定するため、basenameは実際には必要なツールではありません。

文字列からデータを抽出する従来のツールはexprです。

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

ただし、最新のシェル(zshbashkshashyash、すべてPOSIX準拠のshなど)。 ..)そのための組み込み演算子があるので、最近はexprはほとんど必要ありません(そして、いくつかの問題があるので避けるのが最善です)。

${var%pattern}

$varの末尾から(最小の)パーツマッチングパターンを削除します

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

tcshzshのようなシェルには、拡張子を削除する演算子があります。 Zsh:

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

r for rootname)。

拡張機能を削除したい場合は、それがjpg/png/gifのいずれかである場合にのみ、それはより複雑になり、シェルに依存します。

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]...に置き換えることができます。一部のシェル/ツールでは、大文字と小文字を区別しないマッチングを行うこともできます。

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')
13