2010-08-23 15 views
21

¿Hay alguna manera de que un archivo por lotes (en este caso, ejecutando en Windows XP) determine si se inició desde una línea de comando (es decir, dentro de una ventana de la consola) o se inició a través del shell (por ejemplo, haciendo doble clic)?¿Pausa de un archivo por lotes cuando se hace doble clic pero no cuando se ejecuta desde una ventana de la consola?

Tengo un script que me gustaría tener pausa en ciertos puntos cuando se ejecuta a través del shell, pero no cuando se ejecuta en una línea de comandos. He visto a similar question en SO, pero no puedo utilizar la misma solución por dos razones: primero, si se detiene o no debe depender de múltiples factores, de los cuales solo uno es si se hizo doble clic. En segundo lugar, distribuiré este script a otros miembros de mi equipo y no puedo pedirles a todos realistas que realicen cambios en el registro que afectarán a todos los scripts.

¿Esto es posible?

+0

La otra respuesta no sugieren un cambio en el registro. Solo cambiando la línea de comando que se ejecuta en un acceso directo. De acuerdo, eso no te ayudará mucho si haces doble clic en el archivo de lote real. – Joey

+0

@Joey - Tienes razón; Estaba combinando la respuesta y su primer comentario. ;-) –

Respuesta

32

encontrado uno :-) - Después de pensar desesperadamente de lo que podría hacer cuando cmd ejecutar de manera interactiva pero no cuando el lanzamiento de un archivo por lotes directamente ... Finalmente encontré uno.

La pseudovariable %cmdcmdline% contiene la línea de comando que se utilizó para iniciar cmd. En caso cmd se inició normalmente esto contiene algo parecido a lo siguiente:

"C:\Windows\System32\cmd.exe" 

Sin embargo, al iniciar un archivo por lotes que tiene este aspecto:

cmd /c ""C:\Users\Me\test.cmd" " 

pequeña demostración:

@echo off 
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1 
if defined DOUBLECLICKED pause 

Sin embargo, esta forma de comprobación puede no ser la más sólida, pero /c solo debe estar presente como argumento si se inició un archivo por lotes directamente.

Works on my machine http://hypftier.de/dump/works_on_my_machine.png

prueba aquí en Windows 7 x64. Puede o no funcionar, romperse, hacer algo raro, comer niños (podría ser algo bueno) o morderse en la nariz.

+0

Bah. Solo estaba jugando con algo similar, pero estaba tratando de determinar si '% CMDCMDLINE%' contenía '% 0'. Comprobar por '/ c' es * así que * mucho más fácil, sin embargo, y no puedo pensar en ningún caso marginal en el que mi enfoque hubiera funcionado, pero esto no sería así. ¡Gracias! –

+2

@Ben: Pensé en la cosa '% 0' también, pero lamentablemente se rompe. Cuando ejecuto '% cmdcmdline%' a través de 'for', la ruta y el nombre del lote se dividen en dos tokens, ya que mi directorio de inicio contiene espacios y la línea de comando tiene comillas dobles, como se puede ver arriba, lo que arroja' for' off . Otra opción podría ser usar 'echo.% Cmdcmdline% | findstr/i/c:"% ~ 0 "> nul 2> & 1 && set DOUBLECLICKED = 1' (o quizás' || ', siempre cometo errores con' findstr '), que realmente buscaría'% 0' en lugar de confiar en tokenizing. Aún así, fallaría si el lote fuera llamado por otro lote. – Joey

+0

- Estaba usando trucos de subcadena en lugar de 'FOR', pero el lote no es adecuado para la manipulación de cadenas. Tu truco '/ c' es mucho más simple y fácil y debería funcionar a menos que el usuario esté haciendo algo * realmente * raro. –

2

Un enfoque podría ser la creación de un archivo autoexec.nt en la raíz de C: \ que se ve algo como:

@set nested=%nested%Z 

En su archivo por lotes, comprobar si anidado%% es "Z" - si es "Z" y luego has hecho doble clic, así que haz una pausa. Si no es "Z", va a ser "ZZ" o "ZZZ", etc. ya que CMD hereda el bloque de entorno del proceso principal.

-Oisin

+0

Una idea interesante, pero parece que no funciona. 'AUTOEXEC.NT' parece ignorarse por completo,' AUTOEXEC.BAT' se ejecuta solo una vez (al inicio del sistema) y la clave de registro AutoRun se ejecuta una vez por sesión 'CMD.EXE', independientemente de cómo se lanzó. –

+1

Los archivos por lotes no se inician en un nuevo proceso 'cmd'. Así que si acabo de abrir una instancia de 'cmd' y comenzar el archivo por lotes desde allí,' anidado' será 'Z'. De lo contrario, es una buena idea para detectar conchas anidadas, pero no es adecuado para archivos por lotes. – Joey

+0

Otra nota: 'autoexec.nt' nunca residió en el directorio raíz de la unidad, sino en'% systemroot% \ system32'. Hasta donde sé, solo afecta a 'command.com', no a' cmd'. – Joey

0

Un poco más de información ...

comienzo con un archivo batch (test.cmd) que contiene:

@echo %cmdcmdline% 

Si hago doble clic en el por lotes "test.cmd" archivo desde el Explorador de Windows, la pantalla de echo% CMDCMDLINE% es decir:

cmd /c ""D:\Path\test.cmd" " 

al ejecutar el "test.cmd" archivo por lotes desde una ventana de símbolo del sistema, la pantalla de
echo% cmdcmdline% depende de cómo se inició la ventana de comandos ...

Si comienzo "cmd.exe" haciendo clic en "Inicio-Orb" y "Símbolo del sistema" o si hago clic en "Inicio-Orb" y ejecuto "cmd.exe" desde el cuadro de búsqueda/ejecución. Luego ejecuto el "test.cmd" archivo por lotes, la pantalla de echo% CMDCMDLINE% es decir:

"C:\Windows\system32\cmd.exe" 

Además, para mí, si hago clic en "Símbolo del sistema" desde el acceso directo del escritorio, a continuación, ejecutar el " test.cmd" archivo por lotes, la pantalla de echo% CMDCMDLINE% es también:

"C:\Windows\system32\cmd.exe" 

Pero, si yo "Haga clic en" el interior de una ventana del Explorador de Windows y seleccione "Open Command Prompt Here", a continuación, ejecutar el archivo por lotes "test.cmd", la visualización de echo% cmdcmdline% es:

"C:\Windows\System32\cmd.exe" /k ver 

Por lo tanto, solo tenga cuidado, si inicia "cmd.exe" desde un acceso directo que contiene una "/ c" en el campo "Objetivo" (improbable), entonces la prueba en el ejemplo anterior no podrá probar este caso correctamente .

3

Una respuesta consolidada, derivada de gran parte de la información que se encuentra en esta página (y algunas otras páginas de desbordamiento de pila con preguntas similares). Éste no se basa en detectar/c, sino que realmente verifica el nombre del script en la línea de comando. Como resultado, esta solución no se detendrá si hace doble clic en otro lote y luego llama a este; tenía que hacer doble clic en este archivo de lote en particular.

:pauseIfDoubleClicked 
setlocal enabledelayedexpansion 
set testl=%cmdcmdline:"=% 
set testr=!testl:%~nx0=! 
if not "%testl%" == "%testr%" pause 
  1. La variable "Testl" tiene la línea completa de la llamada procesador cmd, excluyendo todas las comillas dobles molestos.
  2. La variable "testr" toma "testl" y quita el nombre del archivo de lote actual si está presente (que será si el archivo de proceso por lotes fue invocado con un doble clic).
  3. La instrucción if ve si "testl" y "testr" son diferentes. En caso afirmativo, se hizo doble clic en el lote, por lo tanto, pause; si no, el lote fue ingresado en la línea de comando (o llamado desde otro archivo por lotes), continúa.

Editar: El mismo se puede hacer en una sola línea:

echo %cmdcmdline% | findstr /i /c:"%~nx0" && set standalone=1 

En la llanura Inglés, este

  • tubos el valor de %cmdcmdline%-findstr, que luego busca el nombre del script actual
  • %0 contiene el nombre del script actual, por supuesto, sólo si shift no ha sido llamado con anterioridad
  • %~nx0 extractos nombre del archivo y la extensión de %0
  • >NUL 2>&1 silencia findstr mediante la reorientación de cualquier salida a NUL
  • findstr establece una nivelevel distinto de cero si no puede encontrar la subcadena en la pregunta
  • && solo se ejecuta si el comando anterior retornó sin error
  • , como consecuencia, no standalone se definirá si el guión se inicia desde la línea de comandos

Más adelante en la secuencia de comandos que podemos hacer:

if defined standalone pause 
+0

Agradable, me gusta el- ¡transatlántico! Esto funciona en Windows 7. Si no usa "shift", puede incluso llamar directamente a 'ECHO% cmdcmdline% | findstr/i/c: "% ~ nx0"> NUL 2> & 1 && PAUSE' al final de la secuencia de comandos, sin necesidad de una variable. – EM0

Cuestiones relacionadas