Добавление порядковых номеров в конец имен файлов - сценарий оболочки

Я пытаюсь добавить последовательные четырехзначные числа в конец имен файлов во время сценария переименования. Проблема, с которой я столкнулся, заключается в том, что он заполняет только первый файл, а добавленные числа не являются последовательными. Вот мой сценарий:

Имена начальных файлов:

FILE-1.png
FILE-5.png
FILE-14.png
FILE-99.png
FILE-167.png
FILE-199.png
FILE-278.png
FILE-455.png

Сценарий:

a=`printf '%04d' "1"`

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf output.%04d.$a.png $(echo $i | sed 's/[^0-9]*//g')`;
    let a=a+1 
done

РЕДАКТИРОВАТЬ: я немного изменил сценарий, добавив переменную fmt вверху. Но я все же хотел бы, чтобы он называл второй набор цифр в числовом порядке первого набора чисел, как в моем желаемом выводе ниже.

fmt=output.%04d
n=1

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf $fmt.%04d.png $(echo $i | sed 's/[^0-9]*//g') "$n"`;
    n=$((n+1))
done

Мой новый вывод:

output.0001.0001.png
output.0005.0007.png
output.0014.0002.png
output.0099.0008.png
output.0167.0003.png
output.0199.0004.png
output.0278.0005.png
output.0455.0006.png

Исходный результат:

output.0001.0001.png
output.0005.7.png
output.0014.2.png
output.0099.8.png
output.0167.3.png
output.0199.4.png
output.0278.5.png
output.0455.6.png

Желаемый результат:

output.0001.0001.png
output.0005.0002.png
output.0014.0003.png
output.0099.0004.png
output.0167.0005.png
output.0199.0006.png
output.0278.0007.png
output.0455.0008.png

Как всегда, приветствуется любая помощь!


person VanCityGuy    schedule 10.10.2015    source источник
comment
Не уверен, почему кто-то проголосовал против этого. В нем есть все элементы хорошего вопроса - ввод, желаемый и фактический результат и даже попытка закодировать решение.   -  person ghoti    schedule 11.10.2015


Ответы (2)


Итак ... вы используете printf для форматирования. Хорошее начало. Но вы не используете его постоянно. Часть, которая не отформатирована .. Почему бы просто не отформатировать?

#!/bin/sh

fmt="output.%04d.%04d.png"

cd /${1-$PWD}

n=1
for file in *.png; do
    fn="${file%.*}"; fn="${fn#*-}"
    mv "$file" "$(printf "$fmt" "$fn" "$n")"
    n=$((n+1))
done

Обратите внимание, что первая строка внутри цикла просто удаляет число из $file, сначала снимая все от точки до конца, а затем снимая все от начала до тире. Вам придется отрегулировать это, если ваши файлы на самом деле отформатированы не так, как в вашем вопросе.

О, и с Днем благодарения. :-)


ОБНОВЛЕНИЕ за комментарии

Приведенное выше расширение *.png, очевидно, упорядочит вещи в алфавитном порядке, так что вы FILE-5.png следуете за FILE-455.png и т. Д.

Ряд инструментов может помочь вам получить «естественный» порядок сортировки. В частности, если вы используете Linux, ваши ls и sort, вероятно, исходят от GNU coreutils, что означает, что вы можете ls -v или sort -V получить естественный порядок сортировки. Но вы не указали, что используете Linux, и, кроме того, синтаксический анализ ls - плохая идея. Но внутреннее сопоставление с образцом и расширение имени пути в bash не обрабатывают естественные сортировки.

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

Если вы используете Linux и bash, строку for выше можно заменить на:

shopt -s extglob
ls -v FILE-+([0-9]).png | while read file; do

Это устанавливает параметр оболочки extglob в bash, а затем использует ls -v (который является зависимостью Linux) для отображения ограниченного просмотра файлов. При синтаксическом анализе ls вы не хотите допускать ошибки таких конструкций, как *.png, поскольку вам не нужно тратить время на предсказание того, что произойдет, если внутри имени файла будет новая строка.

Если вы используете FreeBSD или OSX или не используете bash, требуются дополнительные меры, поскольку в оболочке Almquish есть ls -v и нет extglob:

ls -f FILE-*.png | egrep '^FILE-[0-9]+\.png$' | sort -t- -k2n | while read file; do
  if [ ! -f "$file" ]; then
    continue
  fi

Это разбивается следующим образом:

  • ls -f не выполняет сортировку по каталогу. Спецификация файлов несколько ограничивает просмотр.
  • grep используется для принудительного форматирования имени файла, поскольку этот шаблон не может быть полностью представлен в расширении оболочки.
  • sort -t- -k2n разделяет поля дефисом, затем выполняет числовую сортировку по второму полю.
  • if внутри цикла гарантирует, что кто-то нас не обманывает, создавая имя файла, подобное FILE-1.png\nFILE-2.png.
person ghoti    schedule 11.10.2015
comment
Спасибо за вашу помощь, но похоже, что она работает не так, как хотелось бы. В строке 10 я фактически поменял порядок $ n и $ fn, но получил следующее: output.0001.testing4d.pngoutput.0001.testing4d.png Обратите внимание, что сценарий сохраняется как testing.sh, поэтому он каким-то образом включает имя сценария в переименование. - person VanCityGuy; 11.10.2015
comment
Другое дело, что они не сохраняются последовательно: output.0001.testing4d.pngoutput.0001.testing4d.png output.0005.testing4d.pngoutput.0007.testing4d.png output.0014.testing4d.pngoutput.0002.testing4d.png output.0099.testing4d.pngoutput.0008.testing4d.png output.0167.testing4d.pngoutput.0003.testing4d.png output.0199.testing4d.pngoutput.0004.testing4d.png output.0278.testing4d.pngoutput.0005.testing4d.png output.0455.testing4d.pngoutput.0006.testing4d.png - person VanCityGuy; 11.10.2015
comment
В строке fmt= вверху скрипта была опечатка, которую я сейчас исправил; второй % был заменен на $. Не могу найти свои очки несколько дней, извините за путаницу. Не уверен, что происходит с этим последовательным; расширение имени пути в строке for, *.png, должно соответствовать файлам в алфавитном / цифровом порядке. Повторите попытку с восстановленной строкой fmt и посмотрите, соответствуют ли результаты ожидаемым. - person ghoti; 12.10.2015
comment
Спасибо, это дало мне правильный результат, который я искал. Тем не менее, кажется, что они выплевывают их в том порядке, в котором они были в исходном порядке. Есть ли способ сначала выполнить заполнение исходных чисел, а затем в отдельной команде последовательно пронумеровать их в конце? Я думаю, что если он сделает это двумя отдельными командами, он будет правильно отсортирован. Имеет ли это смысл? - person VanCityGuy; 12.10.2015
comment
Добавлены некоторые варианты сортировки. Не знаю, какая у вас операционная система, поэтому я добавил несколько переносимых. - person ghoti; 12.10.2015
comment
Спасибо. Я использую bash 4 в MacOSX, но надеюсь, что сценарий будет перенесен на Linux. Второй вариант, который вы опубликовали в своем обновлении, работал в моих целях. Большое вам спасибо за вашу помощь! - person VanCityGuy; 12.10.2015

Чтобы добавить последовательную нумерацию в конце имен файлов, вы можете использовать следующий пакетный скрипт

@echo off
setlocal EnableDelayedExpansion
set suffix=100
for /F "delims=" %%i IN ('dir /B *.txt') do (
    set /A suffix+=1
    ren "%%i" "%%~ni_!suffix!.txt"

Включено отложенное раскрытие для получения мгновенных значений переменной суффикс внутри цикла.

%% ~ ni используется для получения имени файла без расширения. Чтобы увидеть больше таких параметров, просто используйте 'for /?'

Ссылка на этот вопрос о StackOverflow

person Vishnu Prasad    schedule 31.03.2020