Как узнать расширение(я) файла на основе его содержимого?

Как узнать расширение(я) файла на основе его содержимого?

Я планирую загрузить несколько изображений с веб-сайта, у которых нет расширения, поэтому я хочу добавить его на основе содержимого файла или 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у меня не работает?

Не только для вас. Смотритеэтот вопрос. Один из комментариев там кажется правильным:

Может быть, это просто очень-очень неполная характеристика?

Я не нашел стандартного инструмента Unix для выполнения конвертации, так что ваша идея может оказаться самым простым решением.

Идеей было бы использовать, file --mime-typeа затем создать массив таблиц диспетчеризации, который сопоставляет известные типы MIME с их расширениями, но я бы предпочел более простое и безопасное решение.

Обратите внимание, что такая карта существует, это /etc/mime.types. Смотритеэто еще один вопрос по Unix & Linux SE. На основе одного из ответов я придумал следующую функцию:

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, чтобы получить максимум одно, хотя это может быть не то, что вам нужно.
  • Так что пользовательский файл карты вместо /etc/mime.typesможет быть полезен. Эта команда покажет вам, какие типы mime существуют в текущем каталоге (и подкаталогах):

    find . -type f -exec file -b --mime-type {} + | sort | uniq
    
  • grepне должно совпадать более одного раза (по крайней мере с /etc/mime.types); ^(начало строки) и $'\t'(табуляция) существуют для избежания частичного совпадения. Используйте 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

Связанный контент