ファイルの内容に基づいてファイルの拡張子を取得するにはどうすればよいですか?

ファイルの内容に基づいてファイルの拡張子を取得するにはどうすればよいですか?

拡張子が付いていない画像を Web サイトから大量にダウンロードする予定なので、ファイルの内容または MIME タイプに基づいて拡張子を追加したいと考えています。

file <filename>ファイルタイプの識別はうまく機能しますが、拡張子が必要です。

--extension
      Print a slash-separated list of valid extensions for the file type found.

fileこれはのマニュアルページからのものですが、動作しないようです:

$ file --extension test_text_file.txt
test_text_file.txt: ???

$ file --extension test_png_file.png
test_png_file.png: ???

$ file --extension test_gif_file.gif
test_gif_file.gif: ???

???すでに適切な拡張子が付いているファイルも含め、渡したすべてのファイルを文字通り印刷します。これらはすべて、それぞれの種類の有効なファイルであり、fileなしでも完全に認識されます--extension

なぜfile --extension機能しないのでしょうか。また、ファイルの拡張子を取得するには何を使用すればよいのでしょうか。

file --mime-type既知の MIME タイプをその拡張子にマップするディスパッチ テーブル配列を使用して作成するというアイデアもありますが、私としては、よりシンプルで安全なソリューションの方が望ましいと思います。

答え1

なぜfile --extension私には機能しないのでしょうか?

あなただけではありません。この質問そこに書かれたコメントの 1 つは正しいように思えます。

おそらく、非常に不完全な機能なのでしょうか?

変換を行うための標準的な Unix ツールはまだ見つかっていないので、あなたのアイデアが最も簡単な解決策かもしれません。

file --mime-type既知の MIME タイプをその拡張子にマップするディスパッチ テーブル配列を使用して作成するというアイデアもありますが、私としては、よりシンプルで安全なソリューションの方が望ましいと思います。

そのようなマップが存在することに注意してください/etc/mime.typesこれはUnixとLinux SEに関する別の質問です回答の 1 つに基づいて、次の関数を思いつきました。

function getext() {
   [ "$#" != 1 ] && { echo "Wrong number of arguments. Provide exactly one." >&2; return 254; }
   [ -r "$1" ] || { echo "Not a file, nonexistent or unreadable." >&2; return 1; }
   grep "^$(file -b --mime-type "$1")"$'\t' /etc/mime.types |
      awk -F '\t+' '{print $2}'
}

使用法:

getext test_text_file.txt   # it takes just one argument

ニーズに合わせてカスタマイズし、スクリプトなどを作成します。主な懸念事項:

  • 成功した場合 (終了ステータス0)、出力は空でないか、空 ( でさえない\n) になることがあります。
  • 一部の MIME タイプは複数の拡張子を返します。 を使用するcut -d ' ' -f 1と最大 1 つの拡張子が取得できますが、必要な拡張子が取得されない可能性があります。
  • そのため、 の代わりにカスタム マップ ファイルを使用/etc/mime.typesすると便利です。 このコマンドは、現在のディレクトリ (およびサブディレクトリ) に存在する MIME タイプを表示します。

    find . -type f -exec file -b --mime-type {} + | sort | uniq
    
  • grepは複数回一致してはいけません (少なくとも/etc/mime.types); ^(行頭) と$'\t'(タブ) は部分一致を避けるためにあります。最大で 1 行が取得されるようにするにはgrep -m 1 ...、(またはhead -n 1それ以降) を使用してください。

答え2

言及する価値があると思うが、いくつかのファイルタイプの拡張子が表示される

file --preserve-date --special-files --extension *

結果:

BMP_file:          ???
CPP_file:          ???
FIFO_file:         ERROR: (null)
GZ_file:           ???
HAR_file:          ???
H_file:            ???
HTML_file:         ???
JAR_file:          zip/cbz
JAVA_CLASS_file:   ???
JAVA_JAVA_file:    ???
JPG_file:          jpeg/jpg/jpe/jfif
MKV_file:          ???
MP3_file:          ???
MP4_file:          ???
ODT_file:          ???
PDF_file:          ???
PNG_file:          ???
PPS_file:          ???
SHELL_SCRIPT_file: ???
SO_file:           ???
TIFF_file:         ???
TMP_file_GBQcW:    ???
XML_file:          ???
ZIP_file:          zip/cbz

関連情報