Se escapa el porcentaje de ImageMagick de la línea de comando de Windows

Se escapa el porcentaje de ImageMagick de la línea de comando de Windows

Estoy intentando utilizar ImageMagick desde la línea de comandos en Windows 7 para convertir muchas imágenes a la vez. Me gustaría utilizar la interfaz de opción -set, pero obtengo resultados inesperados. Un breve ejemplo de algunas de las rarezas que estoy viendo es este:

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

Observe que el carácter de subrayado se elimina misteriosamente del nombre del archivo de salida. Puedo usar un símbolo de intercalación (^) para escapar del segundo signo de porcentaje y así conservar el guión bajo:

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

¿Que está pasando aqui? ¿Por qué al insertar el signo de intercalación se conserva el guión bajo? ¿Es el símbolo de intercalación (^) el escape correcto que hay que intentar? ¿Este comportamiento se debe a la expansión de las variables de entorno del shell de comandos o la rareza resulta de la forma en que ImageMagick maneja los porcentajes de escape? De cualquier manera, ¿existen principios generales con respecto al uso de símbolos de porcentaje en los argumentos de la línea de comando que puedan seguirse para generar un comportamiento predecible?

Lo que realmente quiero hacer es una versión del comando anterior con muchas más propiedades configuradas, que pueda manejar muchos nombres de archivos con caracteres especiales como espacios y símbolos de porcentaje, pero parece una tontería intentarlo si no puedo entender este ejemplo mucho más simple. . En última instancia, necesitaré ejecutar el comando desde un programa .NET.

he miradohttp://www.robvanderwoude.com/escapechars.phpyEscapar de % en nombres de archivos/carpetas en la línea de comandospero no pude entender cómo aplicar los consejos a mi problema.

Actualizar

Agregando algunos ejemplos más para responder preguntas en los comentarios de @dbenham y @Synetech.

Mover el guión bajo antes del segundo símbolo de porcentaje, como en el último ejemplo anterior, antes del guión bajo, produce un archivo llamado 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

Escapar el cursor de las comillas circundantes siempre da como resultado helloworld.png, independientemente de dónde se coloquen los cursores:

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

Respuesta1

No puedo explicar del todo el comportamiento extraño que estás viendo. Casi parece que es el resultado del procesamiento porcentual de cmd.exe, pero no coincide del todo con el comportamiento de cmd.exe, según tengo entendido.

Escapar porcentajes dentro de un archivo por lotes es fácil: simplemente duplíquelos. Pero eso no funciona desde la línea de comando. Técnicamente, no hay forma de escapar de un porcentaje en la línea de comando cmd.exe de Windows.

La línea de comando puede expandir los porcentajes de dos maneras:

1) Expandir Variables de entorno.

Si el texto entre dos porcentajes coincide con el nombre de una variable de entorno, entonces la construcción de porcentaje se reemplaza por el valor.

C:\test>set test=hello

C:\test>echo %test%
hello

Si el texto entre los porcentajes no coincide con el nombre de una variable de entorno, se conserva el texto original completo.

C:\test>echo %notDefined%
%notDefined%

La propia documentación de Microsoft afirma que se puede escapar del porcentaje poniendo un signo de intercalación delante.

C:\test>echo ^%test^%
%test%

Pero eso no es realmente escapar al porcentaje. En cambio, busca una variable llamada test^y no la encuentra. Por lo tanto, el texto original no se altera. Luego, los signos de intercalación se eliminan durante el proceso de escape normal. Esto se puede comprobar definiendo una variable con el signo de intercalación en el nombre.

C:\test>set "test^=goodbye"

C:\test>echo ^%test^%
goodbye

El cursor delante del primer porcentaje no hace nada. Puede colocar un signo de intercalación en cualquier lugar entre los porcentajes y evitará la expansión de la variable siempre que no exista ninguna variable con el signo de intercalación en el nombre.

C:\test>echo %te^st%
%test%

Si el texto está entrecomillado, el cursor no se eliminará a menos que también se escapen las comillas.

C:\test>echo "%te^st%"
"%te^st%"

C:\test>echo ^"te^st%^"
"%test%"

La situación es un poco más complicada cuando hay dos puntos. Los dos puntos se utilizan en la expansión de variables para operaciones de sustitución y subcadena. El nombre de la variable es el texto entre el primer porcentaje y los dos puntos.

C:\test>echo %test:el=a%
halo

C:\test>echo %test:~1,2%
el

Si el texto entre el primer porcentaje y los dos puntos no coincide con un nombre de variable, o si el texto entre los dos puntos y el último porcentaje no es una sustitución o construcción de subcadena válida, entonces el texto original se conserva sin sustitución.

C:\test>echo %test:1,2%
%test:1,2%

Este último ejemplo se parece más a su situación. El texto entre el primer porcentaje y los dos puntos no coincide con una variable, y el texto entre los dos puntos y el último porcentaje no es una sustitución o una construcción de subcadena.por lo que se debe preservar toda la construcción,incluyendo el guión bajo. Por esta razón, no veo cómo cmd.exe podría eliminar el guión bajo.Pero el hecho de que agregar un signo de intercalación antes del segundo por ciento conserve el guión bajo me hace sospechar. Realmente me gustaría saber qué sucede si mueves el cursor antes del guión bajo.


2) Expandir PARA variables

No es un problema en su caso, pero los porcentajes también pueden causar problemas si hay un bucle FOR en vigor. En este caso, no hay forma de proteger el porcentaje utilizando un signo de intercalación, porque el signo de intercalación se elimina antes de la expansión de la variable FOR. En este ejemplo, quiero que el resultado diga %A=1, pero no funciona.

C:\test>for %A in (1 2) do @echo ^%^A=%A
1=1
2=2

La forma más conveniente de proteger el porcentaje es introducir otra variable FOR

C:\test>for %C in (%) do @for %A in (1 2) do @echo %CA=%A
%A=1
%A=2

Funciona igual de bien poner el Aen otra variable

C:\test>for %C in (A) do @for %A in (1 2) do @echo %%C=%A
%A=1
%A=2

Actualizar

Una buena forma de comprobar dónde se elimina el guión bajo es poner ECHO antes de su comando. Si el comando original se conserva con el guión bajo, entonces sabrá que la utilidad de conversión debe ser la culpable.

C:\>echo convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_%[filename:bar].png"

El guión bajo se conserva en mi máquina :-)


Si tiene más interés en cómo funciona el analizador de comandos, consultehttps://stackoverflow.com/a/4095133/1012053. Esa respuesta se refiere principalmente al análisis por lotes, pero las reglas son muy similares y una sección al final describe brevemente las principales diferencias.

información relacionada