Проблема пакетного переименования при работе со специальными символами в имени файла

У меня есть несколько сотен *.mp3 файлов в c:\files. Там есть все мыслимые имена файлов, такие как

  • milad.mp3 (хорошее поведение)
  • эй you.mp3 (пробел в имени файла)
  • systemofadown.mp3 (длинное имя файла)
  • howdy (1).mp3 (скобки в имени файла)

и любая комбинация трех последних условий. Я хочу переименовать файлы в 001-test.mp3, 002-mp3, ... Не имеет значения, какой файл получит какое имя. написал командный файл, чтобы сделать переименование. Вот мой код (с добавленными номерами строк):

01  rem @echo off
02  cls
03  set _number=%1
04  lfnfor on
05
06  :F1TO10
07  IF NOT EXIST *.mp3. goto end
08  if %_number% gtr 9 goto F10TO100
09  for /f %%a IN ('dir /b *.mp3') do rename %%~na.mp3 00%_number%-test.mp4
10  set /a _number +=1
11  goto F1TO10
12
13  :F10TO100
14  IF NOT EXIST *.mp3. goto end
15  if %_number% gtr 99 goto F100TO1000
16  for /f %%a IN ('dir /b *.mp3') do rename %%~na.mp3 0%_number%-test.mp4
17  set /a _number +=1
18  goto F10TO100
19
20  :F100TO1000
21  IF NOT EXIST *.mp3. goto end
22  if %_number% gtr 999 goto end
23  for /f %%a IN ('dir /b *.mp3') do rename %%~na.mp3 %_number%-test.mp4
24  set /a _number +=1
25  goto F100TO1000
26
27  :end
28  for /f %%a IN ('dir /b *.mp4') do rename %%~na.mp4 %%~na.mp3
29  echo Done

Этот код прекрасно работает для имен файлов с хорошим поведением (т.е. без пробелов, без скобок, длиной не более 8 символов). Но если у меня есть хотя бы один файл с плохим поведением имени файла, скрипт ломается (он бесконечно зацикливается, пока я не остановлю его с помощью Ctrl-C).

Проблема, очевидно, в имени файла. Как это можно исправить? Есть идеи? Я был бы очень признателен за любую помощь.

8 ответов

Решение

Прежде всего я хотел бы поблагодарить друзей, которые предложили помощь через ответы. Но ни один не был тем, что я искал. На самом деле я пришел к безупречно работающему сценарию, используя помощь, предоставленную Spire, опубликованную в качестве ответа на этот вопрос.

Вот окончательный код: (на этот раз не нужны номера строк)

rem @echo off
cls
set _number=%1

:F1TO10
IF NOT EXIST *.mp3. goto end
if %_number% gtr 9 goto F10TO100
for /f "usebackq delims=" %%x in (`dir /b *.mp3`) do rename %%~nsx.mp3 00%_number%-test.mp9
set /a _number +=1
goto F1TO10

:F10TO100
IF NOT EXIST *.mp3. goto end
if %_number% gtr 99 goto F100TO1000
for /f "usebackq delims=" %%x in (`dir /b *.mp3`) do rename %%~nsx.mp3 0%_number%-test.mp9
set /a _number +=1
goto F10TO100

:F100TO1000
IF NOT EXIST *.mp3. goto end
if %_number% gtr 999 goto end
for /f "usebackq delims=" %%x in (`dir /b *.mp3`) do rename %%~nsx.mp3 %_number%-test.mp9
set /a _number +=1
goto F100TO1000

:end
for /f %%a IN ('dir /b *.mp9') do rename %%~na.mp9 %%~na.mp3
echo Done.

Пытаться %%~fsa.mp3 вместо %%~na.mp3,

как указано в конце в http://www.ss64.org/viewtopic.php?id=93

или добавить кавычки к длинному имени..

Как насчет замены его на хороший простой скрипт ruby?

Dir["*.mp3"].each_with_index{ |filename,index|
  File.rename filename, "Test-#{index}.mp3"
}

Вы пытались поставить кавычки вокруг имен файлов for найденный?

rename "%%~na.mp3" вместо rename %%~na.mp3?

Windows Vista поддерживает массовое переименование. Просто выберите все элементы в окне проводника и нажмите F2. Введите имя файла, который вы хотите (в данном случае "тест") и нажмите Enter. Бэм, все переименованы.

Это по крайней мере нормализует это для вас. Затем вы можете написать скрипт, который помещает кавычки вокруг всего, например, "%1", "%%~na.mp3" и т. Д., И все готово.

Принципиальная проблема заключается в том, что в качестве разделителя слов используется пробел, т. Е. "Foo bar.txt" считается ДВУМЯ файлами.

Вам нужно как-то корректно экранировать аргументы для cmd.exe, поэтому вам нужно проверить документацию... К сожалению, для вас весь остальной мир продвинулся дальше и предпочитает использовать любое количество альтернативных оболочек (черт, даже bash на cygwin) или, как предложил Крис, вместо этого использовать другой язык.

Ruby, Python и Perl - хороший выбор.

Если вы не возражаете против использования файла сценария Windows, вы можете очень легко выполнить эту функцию, и, возможно, ее будет легче читать / обновлять.

var path = "c:\\files";
var io = new ActiveXObject("Scripting.FileSystemObject");

Enumerator.prototype.each = function(f, c) {
  for (var i = 0; !this.atEnd(); this.moveNext()) {
    if (f.call(c, this.item(), i++, this)===false) break;
  }
  return this;
};

function fixedLength(n) {
  return (n < 100 ? "0" : "") + (n < 10 ? "0" : "") + n;
};

var results = [];
new Enumerator(io.GetFolder(path).Files).each(function(file, index) {
  var oldName = file.Name, newName = fixedLength(index+1) + ".mp3";
  if (/\.mp3$/i.test(oldName)) {
    // mp3 extension
    file.Name = newName;
    results.push(newName + " <-- " + oldName);
  }
});

WScript.Echo(results.join("\n"));

просто сохраните как renameMP3s.js или любой другой файл.js и дважды щелкните.

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

Не вижу ни одной веской причины для того, чтобы тратить время на написание для этого нового пакетного файла.

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