Как переименовать большое количество файлов - PullRequest
8 голосов
/ 05 июня 2010

У меня есть каталог с такими файлами

a.JPG
b.JPG
c.JPG

Я хотел бы выполнить что-то вроде этого

git mv a.JPG a.jpg

Я пытался использовать xargs и другие инструменты, но, похоже, ничего не работает.

Ответы [ 4 ]

9 голосов
/ 07 июня 2010

Суть решения будет заключаться в использовании инструмента / метода, который автоматизирует массовое переименование.Вы можете использовать mv в сочетании с git add или просто git mv .В любом случае вам, возможно, придется предпринять дополнительные шаги, если вы используете нечувствительную к регистру файловую систему.Поэтому, прежде чем приступить к массовому переименованию, может быть полезно обсудить, как немного обрабатывается регистр.

Чувствительность к регистру

Некоторые системы (или комбинации система + файловая система - как вариант по умолчанию дляФайловая система HFS + в Mac OS X *) сохраняет регистр, но не учитывает регистр.В таких системах вам может потребоваться быть осторожным при создании переименований, которые включают только изменение регистра имени.Обычный обходной путь заключается в использовании временного имени, которое отличается более чем просто регистром, в качестве «моста» между двумя именами, которые отличаются только регистром (например, mv foo.JPG tmp && mv tmp foo.jpg).

* Это возможноиспользовать чувствительные к регистру файловые системы в Mac OS X (включая регистрозависимый вариант HFS +).

С этого момента я буду считать файловую систему без учета регистра.

* * 1022Команда * mv в Mac OS X может обрабатывать переименования только с учетом регистра за один шаг.При запуске с параметром -i он выдаст запрос «перезаписать?» И пропустит переименование, если указан параметр -n.Он только успешно выполняет стандартную операцию «достаточно веревки, чтобы повеситься» во многих частях Unix-подобных систем.

Команда git mv немного более параноидальна в этой ситуации.Он отклоняет операцию (ошибка «пункт назначения существует»), если не указан параметр -f / --force.

# this will succeed, though it may fail/prompt if mv is aliased to use -n/-i
mv foo.JPG foo.jpg

# this will succeed
mv -f bar.JPG bar.jpg

# this will succeed but give a warning
git mv -f quux.JPG quux.jpg

Параметры массового переименования

Переименование Perl

Требуемыйоперация достаточно проста, чтобы выполнить ее с помощью небольшого количества сценариев оболочки, но вы можете получить утилиту Perl rename (которую упоминает Джордан Льюис), если вам нужно сделать что-то более сложное.Вы можете попробовать переименовать из пакета Debian perl , или, если вы хотите использовать CPAN, вы можете установить File :: Rename , которая включает в себя программу rename .

ksh , bash , zsh , dash

-ef, используемый ниже, не совместим с POSIX.Аналогично, хотя -e указано в POSIX, оно не является чисто Bourne-совместимым.Оба они широко поддерживаются.

for f in *.JPG; do
    ff="${f%.JPG}.jpg"
    test -e "$f" || continue        # possible when not using nullglob
    test "$f" != "$ff" || continue  # possible when using nocaseglob
    if test -e "$ff" &&
       ! test "$f" -ef "$ff"; then  # possible on a case sensitive filesystem
        echo "skipping <$f>: destination <$ff> exists and is distinct" 1>&2
        continue
    fi

    # "mv" with "git rm" and "git add"
    mv -f "$f" "$ff"     &&
    git rm --cached "$f" &&
    git add "$ff"
done

Последний раздел ( mv , git rm , git add ) можно заменитьпросто git mv :

    # "git mv"
    git mv -f "$f" "$ff"

Если вы очень обеспокоены тем, как может произойти сбой переименования в системах без учета регистра, вы можете использовать временное имя:

    # temp-based "mv" with "git rm" and "git add"
    t="$ff.tmp"; while test -e "$t"; do t="$t.tmp"; done
    mv -n "$f" "$t"      &&
    mv -n "$t" "$ff"     &&
    git rm --cached "$f" &&
    git add "$ff"

Или с git mv :

    # temp-based "git mv"
    t="$ff.tmp"; while test -e "$t"; do t="$t.tmp"; done
    git mv "$f" "$t"  &&
    git mv "$t" "$ff"

zsh / zmv

Это нужно -f для обоих zmv и git mv .

zsh -c 'autoload zmv && $0 $@' zmv -fp git -o 'mv -f' '(*).JPG' '$1 x.jpg'

Теперь, когда все они переименованы и обновлены в индексе Git, вы можете их зафиксировать.

Но смогут ли другие пользователи Git, использующие файловые системы, чувствительные к регистру, проверить их?

проверка git После переименования только для регистра

Если естьдругие пользователи вашей истории, вероятно, все еще будут иметь файлы JPG, и когда они в конечном итоге получат (потомок) ваш коммит с файлами jpg.Что с ними будет?

Независимо от того, что произойдет, нет необходимости «переименовывать в temp, commit, переименовывать в final, commit». git checkout не применяет коммиты в последовательности при переходе между коммитами.Это действительно работает путем «слияния» индекса и рабочего дерева из HEAD в новый коммит.Это фактически означает, что он «переходит» непосредственно к новому коммиту, перетаскивая несогласованные изменения, обнаруженные между HEAD и индексным / рабочим деревом.

Внутренне Git просматриваетимена как удаление и дополнение. Я не нашел никакой документации, описывающей поведение git checkout относительно порядка удалений и добавлений, поэтому я посмотрел на исходный код. git checkout обрабатывает все удаления перед любыми обновлениями / добавлениями (cmd_checkout -> switch_branches -> merge_working_tree (-> reset_tree) -> unpack_trees -> check_updates ).

Вы можете проверить это сразу после переименования:

git checkout HEAD~ # note: detached HEAD
# verify that the original names are back in place
git checkout -     # back to your branch
# verify that the new names are in place again

Казалось, что git blame в файле указывает на вероятную фиксацию: Сделать распакованное дерево обновлять удаленные файлы перед любыми обновленными файлами , который впервые был выпущен в Git 1.5.6- rc0 (2008-06-18). Таким образом, хотя это недокументированное (?), Это поведение было реализовано специально для поддержки нечувствительных к регистру файловых систем.

Спасибо, Линус!

3 голосов
/ 05 июня 2010

Возможность изменения регистра файла зависит от вашей файловой системы. Даже если это работает в вашей файловой системе, вы можете вызвать проблемы с обновлением других людей. Лучше всего их переименовать, зафиксировать, а затем переименовать обратно. Измените все на * .tmp с помощью следующего скрипта bash:

for i in *.JPG; do mv $i ${i%.JPG}.tmp; done

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

Затем переименуйте их обратно в * .jpg аналогичным способом.

2 голосов
/ 05 июня 2010

Используйте стандартную утилиту Linux rename (1). После того, как вы переименовали файлы, добавьте git.

1 голос
/ 05 июня 2010

Возможно, переименуйте их в * .somethingelse, а затем переименуйте обратно в * .jpg

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...