Переименуйте несколько файлов, используя скрипты Bash

27

Я хочу переименовать несколько файлов в одном каталоге, используя сценарии Bash. Имена файлов следующие:

file2602201409853.p
file0901201437404.p  
file0901201438761.p  
file1003201410069.p  
file2602201410180.p

Я хочу переименовать в следующий формат:

file2503201409853.p
file2503201437404.p  
file2503201438761.p  
file2503201410069.p  
file2503201410180.p

Я читал о команде переименования, и попытался сделать это таким образом, но она ничего не делает, я думаю, у меня есть вопросы по поводу синтаксиса. Затем я прочитал, что вы можете сделать цикл с помощью команды mv следующим образом:

for file in cmpsms*2014*.p; do
    mv "$file" "${file/cmpsms*2014*.p/cmpsms25032014*.p}"
done

Но я не могу переименовать файлы. Что я делаю не так?

franvergara66
источник
2
Вы не можете иметь шаблонное выражение справа от выражения замены расширения параметра. Что вы ожидали быть там, где это *?
Кодзиро
@Kiwy Этот вопрос касается удаления части имени файла. Ergo, весьма сомнительно, дубликат.
CVn
2
В следующий раз, пожалуйста, опишите изменения в именах файлов, которые вы хотите внести (мне пришлось посмотреть на это справедливо, прежде чем увидеть различия и сходства). Примеры хороши, но описание и примеры еще лучше.
CVn

Ответы:

42

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

rename 's/\d{4}/2503/' file*

Это просто соответствует первым 4 числам и заменяет их на те, которые вы указали.

И тестовый набор ( -vnзначит, будьте многословны, но ничего не делайте ), используя ваши имена файлов:

$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
Oli
источник
8
Обратите внимание, что это переименование Perl в Debian и его производных (Ubuntu, Mint,…). В других дистрибутивах Linux renameэто совершенно другой инструмент переименования файлов (который поставляется вместе с Debian rename.ul).
Жиль "ТАК - перестань быть злым"
Если в вашем дистрибутиве нет такого инструмента, посмотрите ответ @Michael Campbell. Я думаю, что каждый дистрибутив заменяет дефолтный, renameкак это делал Debian.
Астерия
25

Это должно сделать трюк:

for f in file*; do mv $f ${f/${f:4:8}/25032014}; done

Он заменяет строку между 4-м и 12-м символом на «25032014».

хаос
источник
это for f in file*; do mv $f ${f/${f:4:4}/2503}; doneтоже работа.
Авинаш Радж
Это мило. Если вы хотите просто заменить слово на слово, оно работает как sed. напримерfor f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Эрик
1
@Eric - я опубликовал твой ответ как альтернативу, потому что я думаю, что он более ясный и элегантный. Если вы тоже хотите опубликовать его как ответ - я удалю свой. Благодарность!
Yehosef
Это дает мне ошибку: «mv: target 'FILE_NAME' не является каталогом»
Aubrey
10

это действительно @ ответ Эрика сверху - но это элегантный ответ, поэтому я публикую его как правильный ответ, чтобы привлечь к нему больше внимания.

for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Yehosef
источник
1
ptrn='file[0-9][0-9][0-9][0-9]2014[0-9][0-9][0-9][0-9][0-9].p'
path=/dir
( set -- "${path}/"${ptrn} ; for f ; do {
    echo "mv ${path}/${f} \
        ${path}/file25032014${f#2014}" 
} ; done )

Это должно сделать свое дело. Примечание - я не имею привычки передавать массовые команды mv - как написано, это просто эхо. Вы должны разобраться, прежде чем это сработает.

mikeserv
источник
1

Простой нативный способ сделать это без зацикливания, с обходом каталога :

find -type f | xargs -I {} mv {} {}.txt

Это переименует каждый файл на месте.

И ниже рабочий пример с распараллеливанием :

find -name "file*.p" | parallel 'f="{}" ; mv -- {} ${f:0:4}2503${f:8}'
dtrckd
источник
Сначала было легко представить лучшее решение. Если вы хотите рабочую команду, выполните:
dtrckd
find -type f -name "file*.p" | parallel 'ext="{}" ; mv -- {} ${ext:0:4}2503${ext:8}'
dtrckd
0

Если вы обнаружите, что часто делаете подобные вещи, посмотрите «rename.pl». Это скрипт на perl, но он позволяет вам просто передавать ему код perl (например, как выражение ///), и он будет выполнять массовое переименование на основе этого выражения или кода.

Здесь есть базовая версия: http://stackoverflow.org/wiki/Rename.pl, но есть и другие версии, плавающие в сети. Это было вокруг целую вечность и целую вечность.

Майкл Кэмпбелл
источник