Какой эффективный способ автоматически добавлять расширения к файлам без расширений?

Какой эффективный способ автоматически добавлять расширения к файлам без расширений?

Сегодня во время обеденного перерыва я написал bash-скрипт, который находит в каталоге файлы без расширений и добавляет к ним расширение.

Скрипт получился довольно длинным, так как я добавил кучу флагов и прочего, вроде выбора каталога и указания, копировать или перезаписывать файл, но основную его функциональность можно воспроизвести просто так:

#recursively find files in current directory that have no extension
for i in $(find . -type f ! -name "*.*"); do
    #guess that extension using file
    extfile=$(file --extension --brief $i)
    #select the first extension in the event file spits something weird (e.g. jpeg/jpe/jfif) 
    extawk=$(echo $extfile | awk -F/ '{print $1}')
    #copy the file to a file appended with the extension guessed from the former commands
    cp -av $i $i.$extawk
done

В моем реальном сценарии все немного аккуратнее — я просто хотел разделить команды, чтобы иметь возможность комментировать, почему я что-то делаю.

Мой вопрос: использование findв сочетании с fileтем способом, который я выбрал, вероятно, не самый надежный способ сделать это — в чемлучшийспособ рекурсивного угадывания и добавления расширений для большой группы различных типов файлов в нескольких каталогах?

решение1

for x in $(find …)терпит неудачу симена файлов, содержащие пробелы (обычно) или подстановочные знаки (нечасто). Никогда не анализируйте вывод find. Используйте -exec.

Зш'szmvудобен для массового переименования.

Давайте создадим команду zmv, которая делает то, что вам нужно. Сначала давайте создадим шаблон поиска:

autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
  • -Cприводит к копированию файлов вместо их перемещения.
  • -o -aпереходит -aк cp.
  • -nозначает не действовать, просто печатать то, что будет сделано. Удалите его, как только будете довольны. Замените его на , -vесли хотите действовать, но также печатать то, что делается.
  • -Qпозволяетквалификаторы globв узоре.
  • (*/)#соответствует нулю или более каталогов. Он использует# оператор глоб( extended_globвсегда включено в zmv).
  • ^*.*использует ^оператор glob для сопоставления файлов, .в имени которых нет символа .
  • (.)— это квалификатор glob, ограничивающий совпадения обычными файлами.
  • будет заменен текстом замены. Это может использоваться $fдля ссылки на исходное имя.

zmvвычисляет все заменяющие имена перед выполнением любой замены и выдает сообщение, если заменяющее имя уже существует или если есть конфликты. Файлы, для которых заменяющее имя идентично исходному, пропускаются.

Теперь давайте создадим текст замены. Мы будем использовать многорасширение параметрафункции.

  1. Запросите fileпродление:$(file --extension --brief -- $f)
  2. Добавьте a .в качестве подготовки к замене: $(echo -n .; file --extension --brief -- $f)
    (Это можно также сделать с помощью расширения параметра: ${:-.$(…)}.)
  3. Если предложено несколько расширений (разделенных косой чертой), оставьте только первое:${$(echo -n .; file --extension --brief -- $f)%%/*}
  4. Если предложенное расширение пустое или ???, откажитесь (замените .или .???на пустую строку):${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}
  5. Добавить добавленное расширение к $f(исходному имени). Если то, что мы добавляем, пусто, файл останется нетронутым.

Получившаяся команда:

zmv -C -o -a -n -Q '(*/)#^*.*(.)' '$f${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}'

Это немного загадочно, и вы можете предпочесть поместить код для генерации замены в функцию и использовать zmv … '$(add_extension $f)'.

решение2

Я думаю, что наиболее эффективным способом является сравнение MIME-типов файла с базой данных, расположенной по адресу /usr/share/mime/globs.

  • шарикив Linux естьрасширение файла. Приведен пример, вывод изфайл globs
application/x-mswinurl:*.url
text/x-mrml:*.mrl
text/x-erlang:*.erl
audio/x-pn-audibleaudio:*.aa
application/x-bzip-compressed-tar:*.tbz2
application/x-netshow-channel:*.nsc
application/x-hdf:*.h4
application/pgp-keys:*.key
text/x-idl:*.idl
text/x-chdr:*.h
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.visio:*.vsd
application/x-hdf:*.h5
video/vnd.mpegurl:*.m4u
  • после описания примера типа --> text/x-erlang, он сообщает Linux, что все файлы следует идентифицировать *.какЭрлангс расширением .erl[glob], поэтому -->*.erl
  • вы можете добавить свои собственные расширения, которые будут учтены в /etc/magicфайле

поэтому выполним команду:

mimetype -bM file
  • bаргумент в пользу того, чтобы просто показать вам type-app/extension(кратко)

  • Mаргумент означаетМагияэто способ, которым Linux проверяет файл в байт-коде, шестнадцатеричном и двоичном формате, чтобы убедиться, что файлы действительно являются тем, чем они себя выдают.

  • mimetypeне возвращает, /jpg/png/webpвозвращает только один тип, и он короче, чемfile --mime-type file

Возврат:

image/webp

последние мысли

mimetypeлучше всего работает сдвоичные файлыкак PDF, изображения, видео. Это потому, что он может проверить двоичный файл, вместо этого, text plainэто просто то, что вам нужно идентифицировать с чем-то, и это более сложно, поэтому текстовые редакторы могут распознавать различные языки программирования, ему нужна помощь от пользователя и серверного языка для каждого языка программирования.

для рекурсии, я думаюдеревоЭто хорошо:

tree -FIi '*.*' | grep -v /$
  • аргумент F— добавить /[слэш] к каталогам, например, folderfolder/
  • аргумент I— выбрать противоположность шаблону *.*[это означает выбрать все файлы с расширением], поэтому противоположность — это не расширение
  • аргумент i— удалить пробелы из вывода дерева
  • grep -vчтобы выбрать обратный порядок, поэтому вы добавляете /аргумент -F кдеревокоманду в начале, чтобы вы могли удалить каталоги и получить только файлы, с расширением /$.

Подробнее здесьтипы пантомимы

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