Переименование большого количества файлов изображений с ударом

Я должен переименовать приблизительно 70 000 файлов. Например: От sb_606_HBO_DPM_0089000 кому: sb_606_dpm_0089000 и т.д.

Диапазон числа идет от 0089000 кому: 0163022. Это - только первая часть имени, которое должно измениться. все файлы находятся в единственном каталоге и пронумерованы последовательно (последовательность изображений). Числа должны остаться неизменными.

Когда я пробую это в ударе, он сереет во мне, что 'Список аргументов является слишком длинным'.

Править:

Я сначала пытался переименовать единственный файл с mv:

mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx

Затем я пытался переименовать диапазон (я изучил здесь на прошлой неделе, как переместить загрузку файлов, таким образом, я думал, что тот же синтаксис мог бы работать на переименование файлов...). Я думаю, что попробовал следующее (или что-то как он):

mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx
16
задан 22 May 2018 в 03:11

9 ответов

Один путь состоит в том, чтобы использовать find с -exec, и + опция. Это создает список аргументов, но повреждает список в как много вызовов по мере необходимости для работы на все файлы, не превышая список аргумента maximum. Это подходит, когда все аргументы будут рассматривать то же. Дело обстоит так с rename, хотя не с mv.

Вы, возможно, должны установить Perl, переименуйте:

sudo apt install rename

Затем можно использовать, например:

find . -maxdepth 1 -exec rename -n 's/_HBO_DPM_/_dpm_/' {} +

Удалить -n после тестирования, для фактического переименования файлов.

25
ответ дан 23 November 2019 в 02:26

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

mmv

Я использовал бы команду mmv от пакета того же имени:

mmv '*HBO_DPM*' '#1dpm#2'

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

mmv 'sb_606_HBO_DPM_*' 'sb_606_dpm_#1'

Если у Вас есть файлы вне требуемого диапазона числа в том же каталоге, Вы могли бы быть более обеспечены с циклом по числам, данным далее вниз в этом ответе. Однако Вы могли также использовать последовательность mmv вызовов с подходящими шаблонами:

mmv 'sb_606_HBO_DPM_0089*'       'sb_606_dpm_0089#1'    # 0089000-0089999
mmv 'sb_606_HBO_DPM_009*'        'sb_606_dpm_009#1'     # 0090000-0099999
mmv 'sb_606_HBO_DPM_01[0-5]*'    'sb_606_dpm_01#1#2'    # 0100000-0159999
mmv 'sb_606_HBO_DPM_016[0-2]*'   'sb_606_dpm_016#1#2'   # 0160000-0162999
mmv 'sb_606_HBO_DPM_01630[01]?'  'sb_606_dpm_01630#1#2' # 0163000-0163019
mmv 'sb_606_HBO_DPM_016302[0-2]' 'sb_606_dpm_016302#1'  # 0163020-0163022

цикл по числам

Если Вы не хотите устанавливать что-нибудь или должны выбрать диапазоном числа, избегающим соответствий вне этого диапазона, и Вы готовы ожидать 74 023 вызовов команды, Вы могли использовать простой цикл удара:

for i in {0089000..0163022}; do mv sb_606_HBO_DPM_$i sb_606_dpm_$i; done

Это работает особенно хорошо здесь, так как нет никаких разрывов в последовательности. Иначе Вы могли бы хотеть проверить, существует ли исходный файл на самом деле.

for i in {0089000..0163022}; do
  test -e sb_606_HBO_DPM_$i && mv sb_606_HBO_DPM_$i sb_606_dpm_$i
done

Отметьте это в отличие от for ((i=89000; i<=163022; ++i)) расширение фигурной скобки действительно обрабатывает начальные нули начиная с некоторого выпуска Bash несколько лет назад. На самом деле изменение, которое я запросил, таким образом, я рад видеть варианты использования для него.

Дальнейшее чтение: Расширение фигурной скобки на страницах информации о Bash, особенно часть о {x..y[..incr]}.

цикл по файлам

Другая опция состояла бы в том, чтобы циклично выполниться по подходящему шарику вместо просто цикличного выполнения по целочисленному рассматриваемому диапазону. Что-то вроде этого:

for i in *HBO_DPM*; do mv "$i" "${i/HBO_DPM/dpm}"; done

Снова это - то mv вызов на файл. И снова цикл по длинному списку элементов, но целый список не передается как аргумент подпроцессу, но обрабатывается внутренне ударом, таким образом, предел не вызовет Вас проблемы.

Дальнейшее чтение: Расширение Параметра Shell на страницах информации о Bash, документируя ${parameter/pattern/string} среди других.

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

for i in sb_606_HBO_DPM_+([0-9]); do
  if [[ "${i##*_*(0)}" -ge 89000 ]] && [[ "${i##*_*(0)}" -le 163022 ]]; then
    mv "$i" "${i/HBO_DPM/dpm}"
  fi
done

Здесь ${i##pattern} удаляет самое долгое соответствие префикса pattern от $i. Тот самый длинный префикс определяется, поскольку что-либо, затем подчеркивание, затем обнуляет или больше нулей. Последний записан как *(0) который является расширенным шаблоном шарика, который зависит от extglob опция установлена. Удаление начальных нулей важно для обработки числа, поскольку основа 10 не базируется 8. +([0-9]) в цикле аргументом является другой расширенный шарик, соответствуя одной или нескольким цифрам, на всякий случай у Вас есть файлы там, которые запускают то же, но не заканчиваются в числе.

11
ответ дан 23 November 2019 в 02:26

Один способ работать вокруг ARG_MAX предел состоит в том, чтобы использовать встроенную оболочку удара printf:

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'

Напр.

rename -n 's/HBO_DPM/dpm/' sb_*
bash: /usr/bin/rename: Argument list too long

но

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'
rename(sb_606_HBO_DPM_0089000, sb_606_dpm_0089000)
.
.
.
rename(sb_606_HBO_DPM_0163022, sb_606_dpm_0163022)
10
ответ дан 23 November 2019 в 02:26
find . -type f -exec bash -c 'echo $1 ${1/HBO_DPM/dpm}' _ {} \;
./sb_606_HBO_DPM_0089000 ./sb_606_dpm_0089000

find в текущем каталоге . для всех файлов -type f и действительно переименуйте найденный файл $1 с заменой HBO_DPM с dmp один за другим -exec ... \;

замена echo с mv для выполнения переименовывают.

7
ответ дан 23 November 2019 в 02:26

Можно сделать это файл файлом (это может занять время) с

sudo apt install util-linux  # if you don't have it already
for i in *; do rename.ul HBO_DPM dpm "$i"; done

Как Perl rename используемый в других ответах, rename.ul имеет также опцию -n или --no-act для тестирования.

6
ответ дан 23 November 2019 в 02:26

Вы могли записать немного сценария Python, что-то как:

import os
for file in os.listdir("."):
    os.rename(file, file.replace("HBO_DPM", "dpm"))

Сохраните это как текстовый файл как rename.py в папке файлы находятся в, затем с терминалом в той папке пойдите:

python rename.py
6
ответ дан 23 November 2019 в 02:26

Так как мы даем опции, вот подход Perl. cd в целевой каталог и выполненный:

perl -e 'foreach(glob("sb_*")){rename $_, s/_HBO_DPM_/_dpm_/r}'

Объяснение

  • perl -e : запустите скрипт, данный -e.
  • foreach(glob){} : выполните то, что находится в { } на каждом результате шарика.
  • glob("sb_*") : возвратите список всех файлов и каталоги в текущем каталоге, имена которого соответствуют шарику оболочки sb*.
  • rename $_, s/_HBO_DPM_/_dpm_/r : волшебство жемчуга. $_ специальная переменная, которая содержит каждый элемент, по которому мы выполняем итерации (в foreach). Таким образом, здесь, это будет каждый найденный файл. s/_HBO_DPM_/_dpm_/ заменяет первое вхождение _HBO_DPM_ с _dpm_. Это работает $_ по умолчанию, таким образом, это будет работать на каждом имени файла. /r означает, "применяют эту замену к копии целевой строки (имя файла) и возвращают измененную строку. rename делает то, что Вы ожидали бы: это переименовывает файлы. Таким образом, все это переименует текущее имя файла ($_) к себе с _HBO_DPM_ замененный _dpm_.

Вы могли записать то же самое как расширенный (и больше читаемого сценария):

#! /usr/bin/env perl
use strict;
use warnings;

foreach my $fileName (glob("sb_*")){
  ## Copy the name to a new variable
  my $newName = $fileName;
  ## change the copy. $newName is now the changed version
  $newName =~ s/_HBO_DPM_/_dpm_/;
  ## rename
  rename $fileName, $newName;
}
3
ответ дан 23 November 2019 в 02:26

Я вижу, что никто не пригласил моего лучшего друга sed стороне :). Следующее for цикл выполнит Вашу цель:

for i in sb_606_HBO_DPM*; do
  mv "$i" "$(echo $i | sed 's/HBO_DPM/dpm/')";
done

Существует много инструментов для такого задания, выбирают то, которое является самым понятным для Вас. Этот прост и легок измененный для удовлетворения этому или другим целям...

3
ответ дан 23 November 2019 в 02:26

В зависимости от вида переименования Вы предполагаете, использование vidir с несколькими редактированием строк может быть удовлетворительным.
В Вашем особом случае Вы могли выбрать все строки в своем текстовом редакторе и удалить _ часть "HBO" имен файлов в немногих нажатиях клавиш.

1
ответ дан 23 November 2019 в 02:26

Другие вопросы по тегам:

Похожие вопросы: