Как сместить числа имени файла без коллизий?

Предполагает, что удар и GNU находят.

mv_preserve_structure() {
  local src_file="$1"
  local dest="$2"
  local rel_dir="$(dirname "$src_file")/"
  rel_dir="${rel_dir#*/}"  # returns "2/3" if rel_dir was "src/2/3"
  mkdir -p "$dest/$rel_dir"
  mv "$src_file" "$dest/$rel_dir"
}

# unlike mv, this requires the destination dir as the first parameter
mv_dirs() {
  local dest="$1"
  shift
  for dir in "$@"; do
    for filename in "$dir"/*; do
      [[ -f "$filename" ]] && mv_preserve_structure "$filename" "$dest"
    done
  done
}

mv_dirs dst src src/1 src/2/3
6
23.05.2017, 15:40
5 ответов

Решение @l0b0 переписывается для лучшей устойчивости:

printf '%s\0' index-*.txt |
  sort --zero-terminated --field-separator - --key 2rn |
  xargs -0r rename --verbose '
    s/^index-([0-9]+)\.txt$/$1/;
    $_="index-" . ($_ + 1) . ".txt"'

Не стесняйтесь включать в свое решение, и я удалю свой ответ позже.

Обратите внимание, что это и решения @l0bo - конкретный GNU, не Unix (GNU Не Unix).

2
27.01.2020, 20:28
  • 1
    Если Вы добавляете a -- параметр в конце и настраивают regex, на который он на самом деле работает $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211-'{1,2,3,4,5,6,7,8,9,10,11}$'\n' –  l0b0 24.09.2012, 17:55

Существует немного известной стандартной команды на Unix, который может помочь нам здесь найти общее решение в нахождении, в котором порядке серия переименовывает, должны быть сделаны: tsort

Скажите, что у нас есть список, переименовывает, чтобы быть сделанным в названном файле renames.txt (принимающий ради демонстрации, что их имя не содержит пробелы):

d a
e f
b e
a c

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

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

b
d
e
a
f
c

Который говорит b должен быть переименован после d после e. Мы можем использовать GNU tac (некоторые системы также имеют tail -r) инвертировать тот порядок:

c
f
a
e
d
b

И присоединитесь, это с нашим списком переименовывает:

tsort renames.txt | tac | awk '
  NR==FNR {
    ren[$1] = $2
    next
  }
  $1 in ren {
    print "mv -i --", $1, ren[$1]
  }' renames.txt -

который дает нам:

mv -i -- a c
mv -i -- e f
mv -i -- d a
mv -i -- b e

к которому мы можем затем передать по каналу sh выполниться.

Обратите внимание однако, что вышеупомянутый код не устойчив в этом, мы не проверяли статус выхода tsort выше для обнаружения циклов и имен файлов не должен содержать специальные символы оболочки.

robustification оставляют как осуществление читателю ;-)

3
27.01.2020, 20:28

Это работает на конкретный случай выше:

rename --verbose 's/^index-([0-9]+)\.txt$/$1/; $_="index-" . ($_ + 1) . ".txt"' $(printf '%s\n' index-*.txt | sort --field-separator - --key 2n | tac)

Но:

  1. это не обрабатывает пробел в именах файлов, и
  2. это было бы намного более сложно для произвольных имен файлов.
1
27.01.2020, 20:28

Не прямой ответ на Ваш вопрос, поскольку Вы упоминаете удар, но с zsh, можно указать порядок сортировки и числовой вид с globbing спецификаторами.

$ echo index-*.txt
index-12.txt index-1.txt index-2.txt index-4.txt
$ echo index-*.txt(n)
index-1.txt index-2.txt index-4.txt index-12.txt
$ echo index-*.txt(nOn)
index-12.txt index-4.txt index-2.txt index-1.txt

Или можно определить собственный порядок сортировки с функцией и использованием index-*(o+that-function).

Также обратите внимание, что zsh имеет свое собственное rename встроенная функция вызвана zmv:

$ zmv -fvQ 'index-(<->).txt(n)' 'index-$(($1-1)).txt'
mv -- index-1.txt index-0.txt
mv -- index-2.txt index-1.txt
mv -- index-4.txt index-3.txt
mv -- index-12.txt index-11.txt

$ zmv -fvQ 'index-(<->).txt(nOn)' 'index-$(($1+1)).txt'
mv -- index-11.txt index-12.txt
mv -- index-3.txt index-4.txt
mv -- index-1.txt index-2.txt
mv -- index-0.txt index-1.txt
1
27.01.2020, 20:28
  • 1
    я ищу решение для Bash, как обозначено тегами. –  l0b0 24.09.2012, 17:45

Для контекста я использую приложение LapseIt Pro для замедленной съемки, и по какой-то причине оно остановилось, затем я перезапустил замедленную съемку, но присвоил ему другое имя проекта, например:-

Proj10 _img0000000x

Мне нужно было переименовать все 3000-ые файлы в предыдущий проект Proj9 _img0000000x и изменить номер в конце, чтобы проект имел непрерывную подачу имени + номера, чтобы я мог отображать все изображения, например, как одно видео проекта

Proj10 _img00000001 --> Proj10 _img00003249 необходимо изменить на Proj9 _img00004325 --> Proj9 _img00007574

В итоге конечный результат выглядит так в папке проекта Proj9 _img00000001 --> ​​Proj9 _img00007574

Если вы используете Mac OSX (я использую Mojave ), вы можете

  1. В Finder выделите все файлы, которые нужно изменить
  2. Щелкните правой кнопкой мыши по выделенному разделу файла
  3. Выберите «Переименовать количество X» элементов
  4. Откроется всплывающее окно «Переименовать элементы Finder»
  5. Это всплывающее окно позволяет легко переименовывать и перенумеровывать, а также использовать несколько других удобных опций.

Я все еще рассматриваю команды командной строки grep/sed/awk/cut & find, но пока описанный выше метод работает (Мне нужно было сделать видео как можно скорее для публикации)

-1
27.01.2020, 20:28

Теги

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