Estoy intentando crear un programa que seleccione un nombre de archivo y luego lo canalice a una variable.
Mi intento:
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
Después de su uso se da
myVar:1.14.4
El plan era que entrara y hiciera eco del comando, así que lo hice así.
@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k
pero todo lo que pasa es
e
¿Qué estoy haciendo mal? Además, ¿hay alguna manera de hacer esto con FOR?
Respuesta1
¿Qué estoy haciendo mal?
Simple: está intentando utilizar una técnica que no funciona ;-) Es imposible utilizar la salida del comando canalizado para establecer variables de entorno en su entorno principal debido a la forma en que funcionan los canales de Windows.
Su script se está ejecutando en un proceso de comando; llamémoslo padre.
Una canalización de Windows inicia dos procesos de comando secundarios, cada uno con su propio espacio de entorno independiente. El lado izquierdo de la tubería se ejecuta en el primer hijo y el derecho en el segundo. La tubería envía la salida del primer hijo como entrada al segundo hijo. El SET /P
define con éxito la nueva variable myVar en el proceso hijo y el SET MYVAR
comando muestra el valor. Excelente.
Pero luego la tubería termina, ambos procesos secundarios finalizan y sus entornos asociados desaparecen. No hay forma de transferir el valor del entorno myVar desde el proceso de canalización secundario al entorno principal.
Hay muchos efectos secundarios sorprendentes del diseño de la tubería de Windows que confunden a cualquiera que no comprenda completamente el mecanismo. Verhttps://stackoverflow.com/q/8192318/1012053para más información. Recomiendo leer la pregunta y todas las respuestas.
¿Hay alguna manera de hacer esto con FOR?
Sí, la forma correcta de capturar la salida de un comando en una variable de entorno es mediante FOR, específicamente FOR /F
como muestra DavidPostill. Aunque hay un problema claro, un problema potencial y una ineficiencia en su código.
No es necesario utilizarlo USEBACKQ
al procesar la salida de un comando. Es más sencillo utilizar comillas simples normales '
en lugar de la marca inversa:for /f %%F in ('yourCommand') do ...
El error es el uso de echo myVar:%myVar%
dentro del cuerpo del bucle FOR. Esto mostrará el valor myVar
que existía antes de que se ejecutara el bucle porque se produce un porcentaje de expansión cuando se analiza la línea y todo el bucle FOR se analiza en un solo paso. Debería habilitar la expansión retrasada ( setlocal enableDelayedExpansion
) y luego usar echo !myVar!
para ver el valor que se estableció dentro del bucle.
Existe la posibilidad de que surja otro problema: FOR /F analizará el valor en tokens delimitados por espacios y solo capturará el primer token. Si el nombre de su archivo contiene espacios, no obtendrá el nombre completo a menos que use la opción DELIMS para no especificar ningún delimitador.
for /f "delims=" %%F in (....) do ....
Pero no es necesario utilizar DIR /B
y FOR /F
. Simplemente puedes usar un FOR
bucle de vainilla sin la /F
opción.
Por ejemplo, lo siguiente simplemente enumerará todos los archivos:
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF
Especifica ~nx
utilizar solo el nombre y la extensión del archivo, descartando la ruta de la unidad y la carpeta.
Normalmente no es necesario utilizar una variable de entorno; simplemente utilice la %%F
variable FOR dentro de su bucle para hacer su trabajo.
Pero si necesita un valor fuera del ciclo por algún motivo, ciertamente puede hacerlo
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"
Pero eso sólo capturará el último archivo que se repite. La variable myVar se sobrescribirá con cada iteración. Su diseño original habría capturado el primer archivo que aparecía en la lista (suponiendo que se hubiera podido hacer funcionar). Ninguna parece una buena idea a menos que sepa con certeza que la carpeta Van1 solo contiene un único archivo.
Si necesita capturar todos los archivos en variables, deberá utilizar una pseudomatriz. Batch no tiene un concepto de matriz formal, pero se puede emular fácilmente. Puede encontrar muchos ejemplos si simplemente busca en la web "matriz de archivos por lotes"