Подтвердить что ты не робот

Преобразование всех расширений файлов в нижний регистр

Я пытаюсь скрыть все мои расширения, независимо от того, что это такое. До сих пор, из того, что я видел, вы должны указать, какие расширения файлов вы хотите преобразовать в нижний регистр. Тем не менее, я просто хочу скрыть все после first последней точки . в имени.

Как это сделать в bash?

4b9b3361

Ответ 1

Решение

Вы можете решить задачу в одной строке:

find . -name '*.*' -exec sh -c '
  a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

Примечание: это будет разбито на имена файлов, которые содержат символы новой строки. Но пока не медведь со мной.

Пример использования

$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT

$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt

Объяснение

Вы найдете все файлы в текущем каталоге (.) с периодом . в его имени (-name '*.*') и запустите команду для каждого файла:

a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"

Эта команда означает: попробуйте преобразовать расширение файла в нижний регистр (что делает sed):

$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt

и сохраните результат в переменной a.

Если что-то было изменено [ "$a" != "$0" ], переименуйте файл mv "$0" "$a".

Имя обрабатываемого файла ({}) передано в sh -c в качестве дополнительного аргумента, и оно отображается внутри командной строки как $0. Это делает script безопасным, так как в этом случае оболочка принимает {} как данные, а не как часть кода, как если она задана непосредственно в командной строке. (Я благодарю @gniourf_gniourf за то, что указал на эту действительно важную проблему).

Как вы можете видеть, если вы используете {} непосредственно в script, возможно иметь некоторые shell-инъекции в именах файлов, что-то вроде:

; rm -rf * ;

В этом случае инъекция будет рассматриваться оболочкой как часть кода, и они будут выполнены.

While-версия

Более четкая, но немного более длинная версия script:

find . -name '*.*' | while IFS= read -r f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Это все еще ломается для имен файлов, содержащих новые строки. Чтобы устранить эту проблему, вам необходимо иметь find, который поддерживает -print0 (например, GNU find) и Bash (так что read поддерживает переключатель -d):

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Это все еще ломается для файлов, которые содержат завершающие символы новой строки (так как они будут поглощены субблоком a=$(...). Если вам действительно нужен надежный метод (и вы должны!), с последней версией Bash (Bash ≥4.0), который поддерживает расширение параметра ,, здесь окончательное решение:

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  base=${f%.*}
  ext=${f##*.}
  a=$base.${ext,,}
  [ "$a" != "$f" ] && mv -- "$f" "$a"
done

Вернуться к исходному решению

Или в одном find go (обратно к исходному решению с некоторыми исправлениями, которые делают его действительно надежным):

find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

Я добавил -type f, чтобы только обычные файлы были переименованы. Без этого у вас все еще могут быть проблемы, если имена каталогов переименованы перед именами файлов. Если вы также хотите переименовать каталоги (и ссылки, каналы и т.д.), Вы должны использовать -depth:

find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

чтобы find выполнял поиск по глубине.

Вы можете утверждать, что неэффективно порождать процесс bash для каждого найденного файла. Это правильно, и предыдущая версия цикла была бы лучше.

Ответ 2

Я получил успех с этой командой.

rename JPG jpg *.JPG

Где rename - это команда, которая сообщает оболочке переименовать каждое вхождение JPG в JPG в текущей папке со всеми именами файлов, имеющими расширение JPG.

Если вы видите, что Bareword "JPG" не разрешен, а "строгие субтитры" используются в (1-й строке 1) линии 1 при таком подходе, попробуйте:

rename 's/\.JPG$/.jpg/' *.JPG

Ответ 3

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

#!/bin/bash

# lowerext.sh    

while read f; do
    if [[ "$f" = *.* ]]; then
        # Extract the basename
        b="${f%.*}"

        # Extract the extension
        x="${f##*.}"

        # Convert the extension to lower case
        # Note: this only works in recent versions of Bash
        l="${x,,}"

        if [[ "$x" != "$l" ]]; then
            mv "$f" "$b.$l"
        fi
    else
        continue
    fi
done

Впоследствии все, что вам нужно сделать, это подать список файлов, которые нужно переименовать на стандартный ввод. Например. для всех файлов под текущим каталогом и любым подкаталогом:

find -type f | lowerext.sh

Небольшая оптимизация:

find -type f -name '*.*' | lowerext.sh

Вы должны быть более конкретными, если вам нужен более конкретный ответ, чем этот...

Ответ 4

Это более короткое, но более общее, в сочетании с другим ответом:

rename 's/\.([^.]+)$/.\L$1/' *

Моделирование

Для моделирования используйте -n, т.е. rename -n 's/\.([^.]+)$/.\L$1/' *. Таким образом, вы можете увидеть, что будет изменено до того, как будут выполнены реальные изменения. Пример вывода:

Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1

Краткое описание синтаксиса

  • Синтаксис rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
  • \.([^.]+)$ означает последовательность ничего, кроме точки ([^.]) в конце строки ($), после точки (\.)
  • .\L$1 означает точку (\.), за которой следует строчная (\L) группа из 1 st ($1)
  • Первой группой в этом случае является расширение ([^.]+)
  • Лучше использовать одиночную кавычку ' вместо двойной кавычки ", чтобы обернуть регулярное выражение, чтобы избежать расширения оболочки.

Ответ 5

Это выполнит задание для вашего .mp3 - но только в рабочем каталоге - однако может использовать имена файлов с пробелами:

for f in *.[mM][pP]3; do mv "$f" "${f%.*}.mp3"; done

Исправление:

for f in *.[mM][pP]3; do [[ "$f" =~ \.mp3$ ]] || mv "$f" "${f%.*}.mp3"; done

Ответ 6

Если у вас установлено mmv (= перемещение нескольких файлов), а ваши имена файлов содержат не более одной точки, вы можете использовать

mmv -v "*.*" "#1.#l2"

Он не получает больше одной точки вправо (так как совпадение algo для * не является жадным в mmv), однако оно правильно обрабатывает () и '. Пример:

$ mmv -v "*.*" "#1.#l2"
FOO.BAR.MP3 -> FOO.bar.mp3 : done
foo bar 'baz' (CD 1).MP3 -> foo bar 'baz' (CD 1).mp3 : done

Не идеальный, но гораздо более простой в использовании и запоминании, чем весь материал find/exec/sed.

Ответ 7

рекурсивно для всего одного тонкого решения:

find -name '*.JPG' | sed 's/\(.*\)\.JPG/mv "\1.JPG" "\1.jpg"/' |sh

Вышеперечисленное рекурсивно переименовывает файлы с расширением "JPG" в файлы с расширением "jpg"

Ответ 8

Если вы используете ZSH:

zmv '(*).(*)' '$1.$2:l'

Если вы получите zsh: command not found: zmv, просто запустите:

autoload -U zmv

И затем повторите попытку.

Благодаря этой оригинальной статье для подсказки о zmv и Документация ZSH для синтаксиса подстановки в нижнем регистре и в верхнем регистре.

Ответ 9

Итак, эти решения, которые выглядят как линейный шум, хороши и все, но это легко сделать из python REPL (я знаю, что OP запросил bash, но python установлен на множество систем, которые имеют bash в эти дни...):

import os
files = os.listdir('.')
for f in files:
    path, ext = os.path.splitext(f)
    if ext.isupper():
        os.rename(f, path + ext.lower())

Ответ 10

Если вы заинтересованы только в некоторых расширениях файлов, таких как преобразование всех расширений более высокого размера "JPG" в нижний регистр "jpg", вы можете использовать утилиту командной строки переименовать. CD в ​​каталог, который вы хотите изменить. Тогда

rename -n 's/\.JPG$/\.jpg/' *

Используйте параметр -n для проверки того, что будет изменено, а затем, когда вы довольны результатами, используйте без этого

rename  's/\.JPG$/\.jpg/' *