シェルスクリプトでファイル名の拡張子を削除するにはどうすればよいですか?


143

次のコードの何が問題になっていますか?

name='$filename | cut -f1 -d'.''

そのまま、リテラル文字列を取得します$filename | cut -f1 -d'.'が、引用符を削除すると何も取得されません。一方、タイピング

"test.exe" | cut -f1 -d'.'

シェルでは、私が望む出力を与えますtest。私はすでに$filename正しい値が割り当てられていることを知っています。私がしたいことは、変数に拡張子なしのファイル名を割り当てることです。


6
basename $filename .exe同じことをします。これは、削除する拡張機能を常に知っていることを前提としています。
mpe 2012

6
@mpe、つまりbasename "$filename" .exe。そうでない場合、スペースを含むファイル名は悪いニュースになります。
Charles Duffy

回答:


113

スクリプト/コマンドでコマンドを実行する場合は、コマンド置換構文を使用する必要があります$(command)

だからあなたのラインは

name=$(echo "$filename" | cut -f 1 -d '.')

コードの説明:

  1. echo変数の値を取得$filenameして標準出力に送信します
  2. 次に、出力を取得し、パイプして cutコマンドに
  3. cutを使用します。文字列をセグメントに分割するための区切り文字(セパレータとも呼ばれます)として-f、出力に含めるセグメントを選択します
  4. 次に、$()コマンド置換は出力を取得し、その値を返します
  5. 戻り値は、次の名前の変数に割り当てられます name

これにより、最初のピリオドまでの変数の部分が得られることに注意してください.

$ filename=hello.world
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello.hello.hello
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello
$ echo "$filename" | cut -f 1 -d '.'
hello

ありがとう。また、echoコマンドを使用する必要があることに気付きました。name =echo $filename | cut -f1 -d'.'
mimicocotopus 2012

17
バックティックはPOSIXで非推奨になってい$()ます。
ヨルダン2012

3
いくつかのキャラクターに到達するためのフォークとパイプは、考えられる最悪のソリューションです。
Jens

39
この回答の問題は、入力文字列にドットが1つしかないことを前提としています...以下の@chepnerの方がはるかに優れた解決策です... name = $ {filename%。*}
Scott Stensland

4
この答えは初心者の特徴であり、広めるべきではありません。chepnerの答えによって記載されているように、組み込みのメカニズムを使用してください
neric

256

パラメータ展開を使用することもできます:

$ filename=foo.txt
$ echo "${filename%.*}"
foo


1
そして、ここで使用しようとしていましたecho -n "This.File.Has.Periods.In.It.txt" | awk -F. '{$NF=""; print $0}' | tr ' ' '.' | rev | cut -c 2- | rev。ありがとう。
user208145

1
これは次のような複数の拡張子を持つファイルで機能しますimage.png.gzか?
Hawker65

11
%.*最後の拡張子のみを削除します。すべての拡張機能を削除する場合は、を使用してください%%.*
chepner 2018

1
これは、受け入れられた回答よりもうまく機能するようです。ファイルに複数のドットがある場合にのみ、最後の拡張子を削ぎ落としますが、cutは最初のドット以降をすべて削除します。
デールアンダーソン


20

ファイル名にドット(拡張子の1つ以外)が含まれている場合は、次のようにします。

echo $filename | rev | cut -f 2- -d '.' | rev

1
ミドルレブを忘れてしまいましたが、一度見たら最高でした!
最高のプーバ2016

ファイル名にドットが含まれていない場合は常に空の文字列を返すよう-scut、に指定されたオプションを使用するとさらに便利です。
Hibou57

1
これは、ドットが含まれているパス、ドットで始まる隠しファイル、または複数の拡張子を持つファイルでも機能するため、私の意見では受け入れられる答えになるはずです。
Tim Krief

20
file1=/tmp/main.one.two.sh
t=$(basename "$file1")                        # output is main.one.two.sh
name=$(echo "$file1" | sed -e 's/\.[^.]*$//') # output is /tmp/main.one.two
name=$(echo "$t" | sed -e 's/\.[^.]*$//')     # output is main.one.two

どちらでも使います。ここでは、最後の.(ドット)の後にテキストが続くと仮定しています。


6
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}

出力:

/tmp/foo.bar.gz /tmp/foo.bar

最後の拡張子のみが削除されることに注意してください。


3

私の推奨はを使用することbasenameです。
Ubuntuではデフォルトで視覚的に単純なコードであり、ほとんどの場合に対応します。

スペースとマルチドット/サブ拡張を処理するためのサブケースをいくつか示します。

pathfile="../space fld/space -file.tar.gz"
echo ${pathfile//+(*\/|.*)}

通常、最初から拡張子を取り除き.ますが、..パスに失敗します

echo **"$(basename "${pathfile%.*}")"**  
space -file.tar     # I believe we needed exatly that

ここに重要な注意があります:

スペースを処理するために、二重引用符内で二重引用符を使用しました。$にテキストを送信するため、単一引用符は渡されません。Bashは珍しく、拡張のために「2番目の「最初の」引用符」と読みます。

しかし、あなたはまだ考える必要があります .hidden_files

hidden="~/.bashrc"
echo "$(basename "${hidden%.*}")"  # will produce "~" !!!  

予想される「」の結果ではありません。それを実現するには、$HOMEまたは/home/user_path/
bashが「異常」であり、「〜」を展開しないため(bash BashPitfallsを検索)

hidden2="$HOME/.bashrc" ;  echo '$(basename "${pathfile%.*}")'

1
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"

出力:

program

これは、3年前のSteven Pennyの回答とどう違うのですか?
gniourf_gniourf

1

chepner回答のコメントでHawker65によって指摘されているように、最も投票されたソリューションは、複数の拡張子(filename.tar.gzなど)も、パスの残りのドット(this.path / withなど)も処理しません。 .dots / in.path.name)。可能な解決策は次のとおりです。

a=this.path/with.dots/in.path.name/filename.tar.gz
echo $(dirname $a)/$(basename $a | cut -d. -f1)

これは、パスを数えないファイル名の最初のドットのインスタンスの前の文字を選択することにより、「tar.gz」を取り除きます。おそらく拡張機能をそのように削除したくないでしょう。
Frotz 2018年

0

コードに関する2つの問題:

  1. 変数に格納する文字列を生成するコマンドを囲むために、 `(バックティック)ではなく '(ティック)を使用しました。
  2. 変数「$ filename」を「カット」コマンドへのパイプに「エコー」しませんでした。

コードを「name = `echo $ filename | cut -f 1 -d '。」に変更します。`"、以下に示すように(ここでも、名前変数の定義を囲むバックティックに注意してください):

$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$> 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.