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


170

私はbashで毎晩ビルドスクリプトを書いています。
1つの小さな障害を除いて、すべてが上手くダンディです。


#!/bin/bash

for file in "$PATH_TO_SOMEWHERE"; do
      if [ -d $file ]
      then
              # do something directory-ish
      else
              if [ "$file" == "*.txt" ]       #  this is the snag
              then
                     # do something txt-ish
              fi
      fi
done;

私の問題は、ファイル拡張子を決定し、それに従って動作することです。問題がifステートメントにあり、txtファイルをテストしていることを知っています。

ファイルの拡張子が.txtであるかどうかを確認するにはどうすればよいですか?


名前にスペースが含まれているファイルがある場合、これは壊れます。
jfg956 2011

Paulの回答に加えて、$(dirname $PATH_TO_SOMEWHERE)$(basename $PATH_TO_SOMEWHERE)を使用して、フォルダーとディレクトリに分割し、ディレクトリのようなものとファイルのようなものを実行できます
McPeppr

回答:


248

「$ fileの最後の4文字は等しい.txtですか?」その場合は、以下を使用できます。

if [ ${file: -4} == ".txt" ]

「:-」修飾子は別のものを意味するため、file:との間にスペース-4が必要であることに注意してください。


1
そのために、Windowsマシンでもcommand.comをcommand.txtに名前変更できます。
ホームトースト、2009年

9
不等式を指定する場合は、追加の角かっこを含めることを忘れないで
ください。if

4
@RamRajamonyなぜ不等式をテストするときに[[を使用する必要があるのですか?
PesaThe

コロンの後のスペースが重要であることを指摘したかった。${var:-4}と同じではありません${var: -4}。varが設定されていない場合、最初の(スペースなしの)は「-4」として展開され、2番目(スペース付き)はvarの最後の4文字を返します。
pbatey

1
bashでは、最初の変数を引用符で囲まない限り、「[:==:単項演算子が必要です」というエラーが発生します。だから、if [ "${file: -4}" == ".txt" ]代わりに。
Giles B

264

作る

if [ "$file" == "*.txt" ]

このような:

if [[ $file == *.txt ]]

つまり、二重括弧で引用符はありません。

の右側==はシェルパターンです。正規表現が必要な場合は、=~thenを使用してください。


15
私はこれについて知りませんでした。==または!=の右側がシェルパターンとして展開されるのは特殊なケースのようです。個人的にはこれは私の答えよりも明確だと思います。
ポールスティーブンソン、

20
私はbashを初めて使用するので、これをマルチ条件ifステートメントで使用する方法を理解するのに少し時間がかかりました。それが誰かを助けるために私はここでそれを共有しています。if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
joelostblom 2015

6
@chefloは、一般的に複数の条件に適しています。この特定のケースでは、を使用することもできますif [[ $file =~ .*\.(csv|png) ]]。これは短く、明確で、追加の拡張機能を追加するのが簡単で、簡単に構成可能にすることができます(「csv | png」を変数に入れることにより)。
jox '29年

4
ファイルを二重引用符で囲むことができます。if [[ "$file" == *.txt ]]ファイルの名前にスペースが含まれている場合は、二重引用符が必要です。
shawnhcorey

受け入れられたものの代わりにこの答えを使うべきですか?
Freedo 2018年

26

Unixシステムでは、.txtファイルが本当にテキストファイルであるかどうか確信が持てません。あなたの最善の策は、「ファイル」を使用することです。多分使用してみてください:

file -ib "$file"

次に、MIMEタイプのリストを使用して、「テキスト」、「アプリケーション」などを取得するMIMEの最初の部分と照合または解析できます。


2
file -i...MIMEエンコーディングが含まれているので、次のものを使用できますfile --mime-type -b ...
Wilf

24

拡張子に依存するのではなく、実際にファイルに関する情報を知りたい場合は、「file」コマンドを使用できます。

拡張機能の使用に慣れている場合は、grepを使用して、一致するかどうかを確認できます。


はい、fileコマンドを認識しています。実際、上記のコマンドの出力に基づいて照合を試みましたが、これらのifステートメントではひどく失敗します。

17

あなたも行うことができます:

   if [ "${FILE##*.}" = "txt" ]; then
       # operation for txt files here
   fi

11
case $FILE in *.txt ) ... ;; esacより堅牢で慣用的に見えます。
tripleee

11

'file'と同様に、ファイル拡張子に関係なく機能する少し単純な 'mimetype -b'を使用します。

if [ $(mimetype -b "$MyFile") == "text/plain" ]
then
  echo "this is a text file"
fi

編集:mimetypeが利用できない場合、システムにlibfile-mimeinfo-perlをインストールする必要があるかもしれません


1
「mimetype」スクリプトがすべてのシステムで使用できるわけではないことを明確にする必要があります。
ギルバートピルツ

完了、libfile-mimeinfo-perlを追加
dargaud '19年

5

Linuxのファイル名で利用可能な拡張子を取得する方法に関する正しい答えは次のとおりです。

${filename##*\.} 

ディレクトリ内のすべてのファイル拡張子を印刷する例

for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
    do  echo ${fname##*\.} #print extensions 
done

あなたの答えは二重のバックスラッシュを使用していますが、あなたの例は単一のバックスラッシュのみを使用しています。あなたの例は正しいですが、あなたの答えは正しくありません。
ギルバートピルツ

3

私はファイルの種類を確認して場所にコピーするbashスクリプトを作成しました。これを使用して、Firefoxのキャッシュからオンラインで視聴したビデオを確認します。

#!/bin/bash
# flvcache script

CACHE=~/.mozilla/firefox/xxxxxxxx.default/Cache
OUTPUTDIR=~/Videos/flvs
MINFILESIZE=2M

for f in `find $CACHE -size +$MINFILESIZE`
do
    a=$(file $f | cut -f2 -d ' ')
    o=$(basename $f)
    if [ "$a" = "Macromedia" ]
        then
            cp "$f" "$OUTPUTDIR/$o"
    fi
done

nautilus  "$OUTPUTDIR"&

ここに提示されているものと同様のアイデアを使用しています。これが誰かに役立つことを願っています。


2

それ'$PATH_TO_SOMEWHERE'はのようなものだと思い'<directory>/*'ます。

この場合、コードを次のように変更します。

find <directory> -maxdepth 1 -type d -exec ... \;
find <directory> -maxdepth 1 -type f -name "*.txt" -exec ... \;

ディレクトリとテキストファイルの名前をもっと複雑にしたい場合は、次のようにします。

find <directory> -maxdepth 1 -type d | while read dir; do echo $dir; ...; done
find <directory> -maxdepth 1 -type f -name "*.txt" | while read txtfile; do echo $txtfile; ...; done

ファイル名にスペースが含まれている場合、次のことができます。

find <directory> -maxdepth 1 -type d | xargs ...
find <directory> -maxdepth 1 -type f -name "*.txt" | xargs ...

これらは、シェルで「ループ」を実行する方法の優れた例です。明示的なforand whileループは、ループ本体をより複雑にする必要がある場合のために予約する方が適切です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.