¿Cuál es la razón por la que ‘…’ no se reconoce como un comando interno o externo, progtwig operable o archivo por lotes?

Tengo un fragmento de una línea que funciona perfectamente en la línea de comandos, pero falla y arroja errores cuando lo ejecuto como parte de un script por lotes.

Los siguientes comandos se comportan como se esperaba, eliminando todas las subcarpetas vacías en la carpeta.

for /f "delims=" %d in ('dir /s /b /ad ^| sort /r') do rd "%d"

Sin embargo, cuando se coloca en un archivo por lotes como ese …

FOR /f "delims=" %%d in ('dir /s /b /ad ^| sort /r') do rd "%%d"

… arroja el error estándar: Sort is not recognised as an internal or external command...

He estado experimentando durante la última hora con y sin escapar de la tubería, cambiando el orden de las opciones, buscando la documentación tanto de dir como de sort , etc., pero todavía no he podido averiguar qué es pasando aquí. El rest del archivo por lotes, que tiene solo unas pocas líneas, funciona bien y esta es la única línea que falla.

¿Alguien puede ayudar? Gracias de antemano, realmente lo agradecería.

A) ¿Cómo funciona el intérprete de comandos de Windows para buscar comandos?

El intérprete de comandos de Windows busca un COMANDO para ejecutar

  1. no es un comando interno de cmd.exe y
  2. se acaba de especificar con el nombre de archivo sin extensión de archivo y sin ruta

para un archivo que coincida con el command.* patrón command.* y que tenga una extensión de archivo en la variable de entorno local PATHEXT

  1. primero en el directorio actual y
  2. luego en todos los directorios de la variable de entorno local PATH .

SORT y FIND y FINDSTR y ROBOCOPY y XCOPY y muchos más comandos no son comandos internos de cmd.exe . Son aplicaciones de consola instaladas con Windows ubicadas en el directorio %SystemRoot%\System32 con el nombre de archivo sort.exe , find.exe , findstr.exe , robocopy.exe , xcopy.exe , …

Dichas aplicaciones de consola disponibles de forma predeterminada en Windows se denominan comandos externos para distinguirlas mejor de las aplicaciones de consola que no están instaladas con el sistema operativo Windows.


B) ¿Cómo se define la variable de entorno PATH?

Hay 3 tipos de variables de PATH :

  1. System PATH que se usa para todas las cuentas y se almacena en el registro de Windows bajo la clave:

     HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment 
  2. PATH usuario que se usa solo para la cuenta actual y se almacena en el registro de Windows bajo la clave:

     HKEY_CURRENT_USER\Environment 
  3. Local PATH que siempre es una copia del PATH local del proceso principal que inició el proceso actual.

Windows concatena el sistema y la PATH usuario con la PATH local para la instancia de Windows Explorer utilizada como escritorio de Windows con los accesos directos en la pantalla del escritorio y el menú de inicio de Windows como interfaz visible para el usuario.

Al iniciar un nuevo proceso, Windows copia la tabla de proceso de las variables de entorno actualmente activas para el nuevo proceso.

El proceso principal no puede modificar las variables de entorno de ningún proceso secundario ni puede un proceso secundario modificar las variables de entorno de su proceso principal.

Esto significa que una vez que se inició un proceso como cmd.exe para la ejecución de un archivo por lotes, el proceso tiene su propio conjunto de variables de entorno que solo el proceso puede modificar. Ningún otro proceso puede modificar las variables de entorno de un proceso ya en ejecución.


C) ¿Qué significa el mensaje de error?

El mensaje de error

‘…’ no se reconoce como un comando interno o externo,
progtwig operable o archivo por lotes.

siempre significa que

  1. el nombre de archivo de un

    • aplicación de consola
    • Aplicación GUI
    • secuencia de comandos (archivo por lotes, secuencia de comandos de PowerShell, secuencia de comandos Perl, VBScript, JScript, …)

    se especificó para la ejecución muy probablemente sin la extensión de archivo y sin la ruta (completa) al archivo ejecutable / script y

  2. Windows no pudo encontrar un archivo que coincida con el patrón FileName.* Con una extensión de archivo indicada en la variable de entorno actualmente activa PATHEXT en el directorio actual o en cualquier otro directorio en la variable de entorno actualmente activa PATH .


D) ¿Cuáles son las posibles razones para este mensaje de error?

Las razones típicas son:

1. El nombre de archivo del archivo para ejecutar se especificó incorrecto debido a un error de tipeo.

Marque carácter por caracter el nombre del comando / ejecutable.

2. El directorio actual es diferente al directorio que contiene el archivo para ejecutar.

Ejecutar echo Current directory is: %CD% en la línea de comandos o agregar esta línea al archivo por lotes sobre la línea de comando que no puede ver cuál es el directorio actual.

3. El ejecutable o script que se ejecuta no está instalado en absoluto.

Verificar la existencia del ejecutable para ejecutar. Algunos paquetes de instalación solo funcionan si antes se instalaron otros paquetes como Java, NPM, PHP, etc.

4. El directorio del archivo para ejecutar no está en PATH en absoluto.

Abra en el Panel de control de Windows la ventana Configuración del sistema , haga clic en Configuración avanzada del sistema en el lado izquierdo, haga clic en el botón Variables de entorno y busque en ambas listas Path y sus valores. Por defecto, Path solo existe en la lista de variables del sistema .

5. Un proceso / aplicación en ejecución no se reinició después de la modificación de la PATH del sistema o del usuario .

El usuario o un instalador realizaron una modificación del sistema PATH o PATH usuario con el comando setx o a través del Panel de control – Sistema – Configuración avanzada del sistema , pero un proceso / aplicación ya ejecutado como un comando abierto o ventana de PowerShell no se cerró / salió y abierto / reiniciado después de la modificación de PATH . Esto es necesario como se describe en detalle en el capítulo F) a continuación.

6. La variable LOCAL PATH se modificó antes en la línea de comando o en el archivo por lotes.

Ejecute la set path en la línea de comandos o agregue este comando al archivo por lotes que se encuentra sobre la línea de comando, que no puede ver los valores actuales de las variables de entorno PATH y PATHEXT .

El último motivo es responsable del comando externo SORT que no se encuentra en la ejecución del archivo de proceso por lotes que contiene algún lugar por encima de set path=...


E) ¿Cómo evitar este mensaje de error?

Lo mejor es codificar un archivo por lotes para que sea independiente en PATH y PATHEXT y el orden de los directorios en PATH que significa que aquí se usa la línea de comando:

 FOR /f "delims=" %%d in ('dir /s /b /ad ^| %SystemRoot%\System32\sort.exe /r') do rd "%%d" 

Cualquier comando externo cuyo ejecutable se almacena en %SystemRoot%\System32 debe especificar en un archivo por lotes con esta ruta de acceso y con la extensión de archivo .exe . Entonces, el intérprete de comandos de Windows no necesita buscar un archivo usando PATH y PATHEXT locales y el archivo de proceso por lotes funciona siempre (siempre que la variable de entorno SystemRoot no se modifique también en el archivo por lotes que nunca he visto).


F) ¿Cuándo se aplica un cambio de PATH del sistema o del usuario a los procesos?

Cuando un usuario abre una ventana de símbolo del sistema a través del menú de inicio de Windows o desde una ventana del Explorador de Windows, el usuario inicia cmd.exe con la opción /K implícita para mantener abierta la ventana de la consola después de terminar un comando que es bueno para depurar un archivo por lotes .

Cuando se hace clic en un archivo por lotes en Windows Explorer, el usuario inicia cmd.exe para procesar el archivo por lotes con la opción /C implícita para cerrar la ventana de la consola después de terminar el procesamiento por lotes, lo que no es bueno para depurar un archivo por lotes ya que los mensajes de error no pueden ser visto en este caso.

En ambos casos, Windows crea una copia de las variables de entorno de la aplicación comenzando con cmd.exe que generalmente es Windows Explorer. Por lo tanto, el proceso de comando iniciado tiene una PATH local cuyo valor es el mismo que el proceso principal para iniciar cmd.exe .

Ejemplo:

  1. Abra una ventana del símbolo del sistema, ejecute el title Process1 y ejecute la set path .
    La salida es PATH y PATHEXT como se define actualmente para la cuenta de usuario actual en la ventana de la consola y ahora tiene el título de la ventana Process1 .

  2. Ejecute el set PATH=%SystemRoot%\System32 y luego vuelva a set path .
    La salida es nuevamente PATH y PATHEXT , pero con PATH contiene solo un directorio ahora.

  3. Ejecute el start "Process2" y ejecute en la nueva ventana de la consola con el título de la ventana Process2 la set path comandos.
    La salida es PATH y PATHEXT con los mismos valores que antes en Process1 .
    Esto demuestra que al iniciar un nuevo proceso se copian las variables de entorno actuales del proceso en ejecución y no lo que Windows mismo ha almacenado actualmente en el registro de Windows.

  4. Ejecute en Process2 el comando set PATH= y el siguiente set path .
    La salida solo es PATHEXT porque la PATH local ya no existe para Process2 .
    Esto demuestra que cada proceso puede modificar sus variables de entorno, incluida la eliminación completa.

  5. Cambie a la ventana Process1 , ejecute el comando set PATH=%PATH%;%SystemRoot% y luego set path .
    La salida es PATH con dos directorios y PATHEXT .

  6. Ejecute el comando start "Process3" y en la ventana abierta con el título Process3 el comando set path .
    La salida es PATH con dos directorios como se define también para Process1 y PATHEXT .

  7. Ejecute en Process3 el comando set PATH=%SystemRoot%\System32 .

Hay 3 procesos de comando que se ejecutan con los siguientes valores para PATH local cuando %SystemRoot% expande a C:\Windows :

Process1 : PATH=C:\Windows\System32;C:\Windows
Process2 : PATH no existe en absoluto.
Process3 : PATH=C:\Windows\System32

Entonces, ¿qué sucede ahora al abrir el Panel de control – Sistema – Configuración avanzada del sistema – Variables de entorno y agregar a la lista de variables de usuario la nueva variable de entorno PATH con valor C:\Temp , o en caso de que ya haya una PATH entorno PATH usuario , editar PATH y anexar ;C:\Temp al valor?

Bueno, siempre que se abra la ventana de diálogo con el título Variables de entorno que muestran las dos listas, no ocurre nada al modificar las variables, hasta que se haga clic en Aceptar para tomar todas las modificaciones en el registro de Windows y cerrar la ventana.

Volvamos a los 3 procesos de comando en ejecución y ejecutamos en Process1 , Process2 y Process3 la set path comandos. Se puede ver:

Process1 : PATH=C:\Windows\System32;C:\Windows
Process2 : PATH no existe en absoluto.
Process3 : PATH=C:\Windows\System32

Nada cambió en los procesos que ya se están ejecutando.

Ningún proceso puede modificar las variables de entorno de un proceso en ejecución.

Abra desde el menú de inicio de Windows una ventana más de símbolo del sistema y ejecute el cuarto comando para procesar la set path comandos. Se puede ver que el PATH local del cuarto proceso de comando ha agregado el directorio C:\Temp ahora.

A continuación, cierre los 4 procesos de comando y elimine el usuario agregado PATH respectivamente, elimine ;C:\Temp de la PATH del usuario si antes ha agregado esta ruta de directorio.

¿Cómo es esto posible si ningún proceso puede modificar las variables de entorno de un proceso ya en ejecución?

¿Cómo se modificó la lista de variables de entorno de la instancia de Windows Explorer que se ejecuta como escritorio de Windows al cerrar la ventana Variables de entorno con el botón OK ?

La respuesta a esas dos preguntas fue dada por eryksun en su comentario.

Después de escribir las modificaciones en el sistema y las variables de usuario en el registro haciendo clic en el botón Aceptar de la ventana Variables del entorno , Windows envía el mensaje WM_SETTINGCHANGE a todas las ventanas de nivel superior para informar a las aplicaciones en ejecución sobre los parámetros modificados del sistema.

Depende de la aplicación si este mensaje de evento es manejado en absoluto y cómo. El Explorador de Windows que se ejecuta como escritorio de Windows lee las variables de entorno del registro y actualiza su lista de variables de entorno en consecuencia. Otras aplicaciones como Total Commander manejan este mensaje también y actualizan sus listas de variables de entorno también. Pero cmd.exe no lo hace, afortunadamente, ya que esto sería realmente problemático.

¿Existe alguna posibilidad de modificar un sistema o variable de usuario con notificación a través de WM_SETTINGCHANGE desde una ventana de símbolo del sistema o un archivo por lotes?

Es posible modificar el valor de registro de una variable de entorno mediante el comando reg add . Pero esto no da como resultado el envío del mensaje WM_SETTINGCHANGE a todas las ventanas de nivel superior. Tales cambios hechos con reg add o con regedit requieren un reinicio de Windows (o al menos un cierre de sesión e inicio de sesión del usuario actual) para tener en cuenta en absoluto.

Pero también está el comando setx que está diseñado para modificar un sistema o variable de usuario y que también envía el mensaje WM_SETTINGCHANGE a todas las ventanas de nivel superior después de que el registro se actualizó de acuerdo con los argumentos especificados. Ejecutar setx /? en una ventana de símbolo del sistema para más detalles. Pero tenga en cuenta que setx no modifica la variable de entorno local del proceso de comando en ejecución. Esto se debe hacer con el set comandos utilizado además de setx .


G) ¿Cómo se maneja la variable de entorno PATHEXT en Windows?

La variable de entorno PATHEXT con la lista de extensiones de archivos es manejada por Windows diferente en comparación con la variable de entorno PATH .

El sistema PATHEXT y el usuario PATHEXT NO están concatenados al PATHEXT local .

Un usuario PATHEXT reemplaza el sistema PATHEXT para todos los procesos que se ejecutan en el entorno de la cuenta que tiene un usuario PATHEXT definido.

Solo se define una variable de entorno PATHEXT sistema de forma predeterminada.


H) ¿Es posible desactivar la búsqueda de archivos en el directorio actual?

El procesador de comandos de Windows busca de forma predeterminada en el directorio actual si el nombre de archivo de script o ejecutable se especifica en la línea de comandos o en un archivo por lotes sin ninguna ruta, lo que significa sin barra invertida \ (o una barra diagonal / gracias a la autocorrección) cadena de argumentos.

Pero en Windows Vista y versiones de cliente de Windows posteriores y en Windows Server 2003 y versiones de servidor de Windows posteriores es posible desactivar la búsqueda de un script / ejecutable en el directorio actual especificado sin al menos una ruta relativa .\ Definiendo la variable de entorno NoDefaultCurrentDirectoryInExePath con cualquier valor escrito por eryksun en su comentario a continuación y explicado por Microsoft en el artículo de MSDN sobre la función NeedCurrentDirectoryForExePath .

Consulte Eliminar el directorio de trabajo actual de la ruta para obtener más detalles sobre el uso de esta variable de entorno.

Lo más probable es que te equivoques con la variable PATH . Tal vez lo está sobrescribiendo en otro lugar en su secuencia de comandos. Dado que sort es un comando externo, opuesto a todos los demás en su línea de comandos como for , dir , rd , que son comandos internos de cmd , la variable PATH es necesaria para encontrar el comando. Si PATH no está definido, los comandos externos se buscan solo en el directorio de trabajo actual. También hay una variable PATHEXT que se necesita para definir extensiones de archivo estándar para ejecutables, como .com , .exe . Por lo tanto, cuando la sort aparece en el símbolo del sistema o en un archivo por lotes, el sistema busca en el directorio de trabajo actual y en todos los directorios especificados por la variable PATH un archivo con la sort nombre base y una de las extensiones especificadas por PATHEXT . La sort comando se llama actualmente sort.exe y generalmente se encuentra en C:\Windows\System32 .