Я пытаюсь использовать ImageMagick из командной строки в Windows 7, чтобы преобразовать много изображений одновременно. Я хотел бы использовать интерфейс опции -set, но получаю неожиданные результаты. Вот короткий пример некоторых странностей, которые я наблюдаю:
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_%[filename:bar].png"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.135
Обратите внимание, что символ подчеркивания загадочным образом удален из выходного имени файла. Я могу использовать каретку (^), чтобы экранировать второй знак процента и сохранить подчеркивание:
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_^%[filename:bar].png"
example.jpg=>hello_world.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.126
Что здесь происходит? Почему вставка каретки приводит к сохранению подчеркивания? Является ли каретка (^) вообще правильным экранированием? Является ли это поведение следствием расширения переменной среды командной оболочки или странность является результатом того, как ImageMagick обрабатывает экранирование процентов? В любом случае, существуют ли общие принципы использования символов процента в аргументах командной строки, которым можно следовать, чтобы вызвать предсказуемое поведение?
На самом деле я хочу сделать версию команды выше с большим количеством наборов свойств, которая может обрабатывать очень много имен файлов со специальными символами, такими как пробелы и символы процента, но кажется глупым пытаться это сделать, если я не могу понять этот гораздо более простой пример. В конечном счете, мне нужно будет выполнить команду из программы .NET.
Я посмотрел наhttp://www.robvanderwoude.com/escapechars.phpиЭкранирование % в именах файлов/папок в командной строкено не мог понять, как применить этот совет к моей проблеме.
Обновлять
Добавляю еще несколько примеров в ответ на вопросы в комментариях от @dbenham и @Synetech.
Перемещение подчеркивания из позиции перед вторым символом процента, как в последнем примере выше, в позицию перед подчеркиванием создает файл с именем hello^world.png
:
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]^_%[filename:bar].png"
example.jpg=>hello^world.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.141u 0:00.132
Экранирование окружающих кавычек всегда приводит к helloworld.png
, независимо от того, где внутри размещены каретки:
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"^%[filename:foo]_^%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.109u 0:00.115
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]_^%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.141u 0:00.143
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"^%[filename:foo]_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.126
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.131
C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]^_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.111
решение1
Я не могу объяснить странное поведение, которое вы видите. Похоже, что это результат обработки процентов cmd.exe, но это не совсем соответствует поведению cmd.exe, как я понимаю.
Экранирование процентов в пакетном файле легко - просто удвойте их. Но это не работает из командной строки. Технически, нет способа экранировать процент в командной строке Windows cmd.exe.
Командная строка может расширять проценты одним из двух способов:
1) Разверните Переменные среды.
Если текст между двумя процентами совпадает с именем переменной среды, то конструкция процента заменяется значением.
C:\test>set test=hello
C:\test>echo %test%
hello
Если текст между процентами не соответствует имени переменной среды, то сохраняется полный исходный текст.
C:\test>echo %notDefined%
%notDefined%
В документации Microsoft утверждается, что можно экранировать процент, поставив перед ним знак «каретка».
C:\test>echo ^%test^%
%test%
Но это не совсем экранирование процента. Вместо этого он ищет переменную с именем test^
и не находит ее. Поэтому исходный текст нетронут. Затем каретки удаляются во время обычной обработки экранирования. Это можно доказать, определив переменную с кареткой в имени.
C:\test>set "test^=goodbye"
C:\test>echo ^%test^%
goodbye
Каретка перед первым процентом ничего не делает. Вы можете разместить каретку в любом месте между процентами, и она предотвратит расширение переменной, пока не будет переменной с кареткой в имени.
C:\test>echo %te^st%
%test%
Если текст заключен в кавычки, то курсор не будет удален, если только кавычки также не экранированы.
C:\test>echo "%te^st%"
"%te^st%"
C:\test>echo ^"te^st%^"
"%test%"
Ситуация немного сложнее, когда есть двоеточия. Двоеточие используется расширением переменной для операций подстановки и подстроки. Имя переменной — это текст между первым процентом и двоеточием.
C:\test>echo %test:el=a%
halo
C:\test>echo %test:~1,2%
el
Если текст между первым процентом и двоеточием не соответствует имени переменной или если текст между двоеточием и последним процентом не является допустимой заменой или конструкцией подстроки, то исходный текст сохраняется без замены.
C:\test>echo %test:1,2%
%test:1,2%
Этот последний пример больше всего напоминает вашу ситуацию. Текст между первым процентом и двоеточием не соответствует переменной, а текст между двоеточием и последним процентом не является подстановкой или конструкцией подстроки,поэтому вся конструкция должна быть сохранена,включая подчеркивание. По этой причине я не понимаю, как cmd.exe может удалять подчеркивание.Но тот факт, что добавление каретки перед вторым процентом сохраняет подчеркивание, вызывает у меня подозрения. Мне бы очень хотелось узнать, что произойдет, если вместо этого переместить каретку перед подчеркиванием.
2) Расширить переменные FOR
В вашем случае это не проблема, но проценты также могут вызывать проблемы, если действует цикл FOR. В этом случае нет способа защитить проценты с помощью каретки, поскольку каретка удаляется до расширения переменной FOR. В этом примере я хочу, чтобы вывод читался как %A=1
, но это не работает.
C:\test>for %A in (1 2) do @echo ^%^A=%A
1=1
2=2
Самый удобный способ защитить процент — ввести еще одну переменную FOR
C:\test>for %C in (%) do @for %A in (1 2) do @echo %CA=%A
%A=1
%A=2
Точно так же можно поместить A
в другую переменную
C:\test>for %C in (A) do @for %A in (1 2) do @echo %%C=%A
%A=1
%A=2
Обновлять
Хороший способ проверить, где удаляется подчеркивание, — поставить ECHO перед командой. Если исходная команда сохраняется с подчеркиванием, то вы знаете, что виновата утилита convert.
C:\>echo convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_%[filename:bar].png"
Подчеркивание на моей машине сохранилось :-)
Если вам интересно узнать больше о том, как работает анализатор команд, см.https://stackoverflow.com/a/4095133/1012053. Этот ответ в основном касается пакетного анализа, но правила очень похожи, а раздел в конце кратко описывает основные различия.