У меня есть несколько файлов с неправильными именами:
$ ls
devoirNote1_1_2.R devoirNote1_1_5.R devoirNote1_4_1.R
devoirNote1_1_3.R devoirNote1_1.R devoirNote1.R
devoirNote1_1_4.R devoirNote1_2_1.R example140.R
Я хочу заменить все DevOirNote1_i_j.R
целыми числами i и j, кроме DevOirNote1_4_1.R
в DevOirNote1_ {i + 1} _j.R
(без изменений оставлен только DevOirNote1_4_1.R
).
Я подумал об использовании команды mv
, например mv DevOirNote1 _ * _ 2.R DevOirNote1_2_2.R
, но когда несколько файлов совпадают (например, если оба DevOirNote1_1_2.R
и DevOirNote1_3_2.R
), это создает проблему.
Следовательно, как создать сценарий или командную строку, которая переименовывает мои файлы, увеличивая одну из переменных в именах файлов, но не все из них?
Для этого можно использовать утилиту Perl rename
(*). Она применяет заданную команду Perl к каждому заданному имени файла и переименовывает файл в то, на что команда изменила имя.
Таким образом, это изменит _1_
на _2_
для всех файлов, которым соответствует glob.
rename 's/_1_/_2_/' devoirNote1_*_2.R
Численное увеличение можно сделать с помощью /e
, модифицировав команду замены, сделав часть замены фрагментом Perl вместо литерала.
rename -v 's/_(\d+)_/"_" . ($1 + 1) . "_"/e' devoirNote1_*_2.R
Это позволит выбрать часть имени файла с цифрами между символами подчеркивания, захватить цифры до $1
и заменить их числом, увеличенным на единицу, с добавлением символов подчеркивания. -v
для режима verbose. Со списком файлов в вашем примере это выведет devoirNote1_1_2.R переименован в devoirNote1_2_2.R
, как и ожидалось.
Затронутыми файлами будут все файлы, которым соответствует glob в конце командной строки.
Хотя обратите внимание, что если у вас есть, скажем, 1_1_2
и 1_2_2
, переименование первого из них будет неудачным, поскольку оно столкнется со следующим. Для этого нужно либо дать имена файлов в обратном порядке, либо сначала изменить их на не коллидирующую форму, а затем обратно, например, добавив дополнительный символ.
(* не инструмент переименования util-linux. См. здесь и здесь)
Скрипт будет излишним для двух (пакетных) ходов. Используйте утилиту mmv
:
mmv devoirNote1_2_"*" devoirNote1_3_#1
mmv devoirNote1_1_"*" devoirNote1_2_#1
Конечно, в таком порядке. Если ходов намного больше, чем два, то сценарий действительно будет предпочтительнее.
Здесь мы используем отрицательный просмотр
, чтобы отфильтровать файлы * Note1_3_2.R
и * Note1_4_2.R
из списка поиска.
OP хотел оставить * Note1_4_2.R
нетронутым => мы также не можем коснуться одного предыдущего файла, а именно * Note1_3_2.R
, поскольку мы некуда это мв.
Логика цикла for
предназначена для выполнения обратной числовой сортировки
по порядковому номеру между 1 и 2, чтобы мы могли выполнить неразрушающую операцию mv.
perl -e '
/(.*)_(\d+)_(.*)/ and
rename $_, join "_", $1, $2+1, $3 or warn "Could not mv the file <<$_>>\n"
for
map { $_->[0] }
sort { $b->[2] <=> $a->[2] || $b->[1] <=> $a->[1] }
map { [$_, /_(\d+)_(\d+)/] }
grep { /^devoirNote1_(?![34]_1.R)\d+_\d+.R/ }
<*.R>
'