рекурсивно добавить расширение файла ко всем файлам

106

У меня есть несколько каталогов и подкаталогов, содержащих файлы без расширения. Я хочу добавить .jpgко всем файлам, содержащимся в этих каталогах. Я видел сценарии bash для изменения расширения файла, но не просто для его добавления. Он также должен быть рекурсивным, может кто-нибудь помочь?

Robjmills
источник

Ответы:

228

Альтернативная команда без явного loop ( man find):

find . -type f -exec mv '{}' '{}'.jpg \;

Объяснение: это рекурсивно находит все файлы ( -type f), начиная с текущего каталога ( .), и применяет команду перемещения ( mv) к каждому из них. Также обратите внимание на кавычки {}, чтобы имена файлов с пробелами (и даже новые строки ...) обрабатывались правильно.

Стефан202
источник
7
В частности, этот работает лучше, если в структуре каталогов находится огромное количество файлов (что заставляет bash расстраиваться из-за длины списка файлов для перебора).
DrAl
@Al, если вы ссылаетесь на forцикл, нарушающий bash, чтобы перебирать список файлов, это неверно. Цикл bash forитеративно выдает каждую mvкоманду.
Ник
Вопрос: Создает ли findсначала список файлов перед выполнением -execоператора? Думаю, да, но я хочу прояснить этот момент перед написанием бесконечных циклов.
Boldewyn
2
эта команда также найдет файлы с расширением. Это то, чего хочет OP?
ghostdog74
1
@ ghostdog74: Поскольку он принял этот ответ, очевидно, что сказанное выше помогло. В противном случае, как вы упомянули ниже, добавление -not -name "*.*"поможет.
Stephan202
62

это найдет файлы без расширения и добавит ваш .jpg

find /path -type f -not -name "*.*" -exec mv "{}" "{}".jpg \;
призрачная собака74
источник
Это определенно обеспечит желаемый результат в 99% случаев. +1
les
9

Это немного поздно, но я подумал, что добавлю лучшее решение (хотя, возможно, менее читаемое), чем те, которые были до сих пор:

find /path -type f -not -name "*.*" -print0 | xargs -0 rename 's/(.)$/$1.jpg/'

Использование find | xargsшаблона обычно приводит к более эффективному выполнению, поскольку вам не нужно создавать новый процесс для каждого файла.

Обратите внимание, что для этого требуется версия переименования, которая есть в дистрибутивах со вкусом Debian (также известная как prename), а не традиционное переименование. Однако это всего лишь крошечный сценарий Perl, поэтому было бы достаточно легко использовать приведенную выше команду в любой системе.

Чад Хьюникатт
источник
4

как это,

for f in $(find . -type f); do mv $f ${f}.jpg; done

Я не ожидаю, что у вас есть имена файлов, разделенные пробелами.
Если вы это сделаете, имена нужно будет немного обработать.

Если вы хотите , чтобы выполнить команду из другого каталога,
вы можете заменить find .с find /target/directory.

Ник
источник
1
В нем отсутствует 'do', и если в имени файла есть пробелы, лучше указать имя файла в кавычках: для f в $ (find. -Type f); сделать mv "$ f" "$ {f} .jpg"; готово
DrAl
и, предположительно, я бы запустил это из каталога верхнего уровня?
robjmills
@seengee: да. Обратите внимание, что эта команда также пропускает черточку -type.
Stephan202
Мне нужно было куда-то пойти и набрать слишком быстро ... сейчас поправляю.
nik
1

Для переименования всех файлов без расширения в Windows basic вы можете сделать. ren * *.jpg Поскольку файл без расширения, просто используйте *, или, если вы хотите изменить png на jpg, используйтеren *.png *.jpg

Нуно
источник
0

rename

не уверен, что он может переименовывать файлы без расширений (сейчас я на Windows 7)

DFA
источник
1
он может, но он также будет переименовывать каталоги, и нет способа указать ему, чтобы он работал рекурсивно в подкаталогах (по крайней мере, с версией, которая у меня есть на Ubuntu).
mirod
Я знаю, по крайней мере, две разные команды rename, одна из которых - программа на языке C, включенная в util-linux-ng, а другая - программа Perl (созданная самим Уоллом) на машинах Debian нашего университета. На самом деле ни один из них не выполняет рекурсию.
Boldewyn