BATCH - Problema en bucle infinito

Iniciado por llAudioslavell, 21 Septiembre 2016, 00:08 AM

0 Miembros y 1 Visitante están viendo este tema.

llAudioslavell

Hola a todos, regreso despues de muchos años a este gran foro.

Tengo unos problemillas con un pequeño script en Batch, les explico en que consiste.
Tengo instalado un agente VPN el cual manualmente me puedo conectar y desconectar dandole doble click. Al realizar este evento se ejecuta un proceso "X". Lo que necesito es que al desconectarse se vuelva a conectar automaticamente, para esto he creado un bucle:

Código (dos) [Seleccionar]
@echo off
:bucle

set ERRORLEVEL=
tasklist | findstr openvpn.exe

if ERRORLEVEL == 1 (
taskkill /IM openvpn-gui.exe
"C:\Program Files (x86)\Sophos\Sophos SSL VPN Client\bin\openvpn-gui.exe" --connect xxxxxxxx@xxxxxxxxxx.xxxx.ovpn
)

goto bucle


Aqui evaluo si el proceso openvpn.exe se encuentra ejecutandose, en el caso que no cierro el programa y lo vuelvo abrir para que se reconecte pero al abrir el programa en la ventana MS-DOS el bucle se queda paralizado, la verdad soy novato en programacion en batch, espero que me puedan ayudar.
Gracias de ante mano.

Eleкtro

#1
Cita de: llAudioslavell en 21 Septiembre 2016, 00:08 AM
Código (dos) [Seleccionar]
if ERRORLEVEL == 1 (...)

El problema está ahí, estás evaluando el texto "ERRORLEVEL", no el valor de la variable dinámica %ERRORLEVEL%. Si comparas el texto "ERRORLEVEL" con "1", obviamente el resultado será negativo puesto que son distintos.

Solución, añádele los símbolos % que faltan en el nombre de la variable:
Código (dos) [Seleccionar]
If "%ERRORLEVEL%" EQU "1" (...)




Aparte de eso, no es conveniente que hagas esto:
Cita de: llAudioslavell en 21 Septiembre 2016, 00:08 AM
Código (dos) [Seleccionar]
set ERRORLEVEL=

Si le hubieses llegado a asignar un valor, entonces habrías sustituido la variable dinámica ERRORLEVEL durante el tiempo de vida de tu script, y jamás podría haber dado como resultado el valor "1", sino el valor que tu le hubieses asignado.
En resumen, elimina esa linea para no caer en malas costumbres, no debes redeclarar variables dinámicas puesto que no tiene sentido hacerlo.

Saludos








llAudioslavell

#2
Lo he modificado y aun no me funciona del todo bien. Creo saber la solucion pero no se como hacerlo ya que no domino este lenguaje, solo una consulta mi estimado.
Como puedo volver a reutilizar la variable ERRORLEVEL o como puedo crear otro, he probado almacenando el valor de ERRORLEVEL  en una variable pero se me dificulta mucho !
Código (dos) [Seleccionar]
@echo off
:bucle

tasklist | findstr openvpn-gui.exe

if %ERRORLEVEL% EQU 1 (
       echo.el proceso openvpn-gui esta cerrado
tasklist | findstr openvpn.exe
if %ERRORLEVEL% EQU 0 (
echo.el proceso openvpn esta abierto
)else if %ERRORLEVEL% EQU 1 (

echo. el proceso openvpn esta cerrado
)
) else if %ERRORLEVEL% EQU 0 (
        echo.el proceso openvpn-gui esta abierto
)


goto bucle


Esto es lo que quiero hacer pero no entra al if anidado o mejor dicho al if del proceso  openvpn-gui.exe.

Esto funciona asi:
openvpn-gui.exe= proceso de la interfaz del agente vpn
openvpn.exe= proceso de la CONEXION del vpn.

Cuando se ejecuta el proceso OPENVPN-GUI se tiene que conectar la vpn, click derecho y conectar, al hacer este evento o sea al establecer la conexion se ejecuta automaticamente el proceso OPENVPN, lo que primero quiero hacer es dar a imprimir si se esta ejecutando o no los dos procesos para luego añadirle el codigo que necesito.
Ayudame porfavor !!!de todos modos seguite intentando, gracias !!




Creo que ahora se entendera un poco mejor mi codigo.


Código (dos) [Seleccionar]
@echo off
:bucle

tasklist | findstr openvpn-gui.exe

set /a indOPENVPN= %ERRORLEVEL%

if %indOPENVPN% EQU 1 (
        echo.interfazClose
tasklist | findstr openvpn.exe
echo %ERRORLEVEL%
if %ERRORLEVEL% EQU 1 (
echo.conexionClose
)else if %ERRORLEVEL% EQU 0 (
echo.conexionOpen
)

) else if %indOPENVPN% EQU 0 (
         echo.interfazOpen
)

goto bucle

goto bucle

Pero no entra al if del proceso openvpn.exe  :( iluminame !! que estoy haciendo mal :(




Di un pasito mas xD
Cuando imprimo  ERROLEVEL, echo %ERRORLEVEL%, porque me imprime 0 cuando el proceso esta cerrado ?  :(

Eleкtro

#3
Primero de nada, esto es un foro donde hay unas reglas de redacción, no importa la experiencia que tengas, si algo has de saber es formatear el código que publiques, usa las etiquetas GeShi.

Por favor, no pidas por mensajes privados que leamos tu post, por más que lo hagas yo no lo voy a leer antes ni después, sinó en su momento.

EDITO: También está prohibido hacer doble y triple post, USA EL BOTÓN MODIFICAR. Por favor, no me des más trabajo, escribe un post como Dios manda.




Cita de: llAudioslavell en 21 Septiembre 2016, 16:52 PMComo puedo volver a reutilizar la variable ERRORLEVEL o como puedo crear otro, he probado almacenando el valor de ERRORLEVEL  en una variable pero se me dificulta mucho !

La variable %ERRORLEVEL% es un valor dinámico que cambia cada vez que termina la ejecución de un comando/executable, se asigna el código de salida a dicha variable dinámica.
No necesitas (ni tampoco podrías) crear una variable que cumpla su misma función, puedes reutilizar la variable %ERRORLEVEL% las veces que quieras, no se va a gastar :xD.




Cita de: llAudioslavell en 21 Septiembre 2016, 16:52 PMno entra al if anidado

Cita de: llAudioslavell en 21 Septiembre 2016, 16:52 PMif %ERRORLEVEL% EQU 1 (
) else if ...

Batch es un lenguaje MUY limitado, simplemente no es posible reproducir una sentencia Else If de manera convencional, así que esa anidación de Ifs no te funcionará.

Batch está limitado a poder usar una sentencia If y un AND, y este último debemos usarlo de forma invisible...




Te aconsejo que modifiques ese código que has escrito, sigue la siguiente estructura y no tendrás por que obtener errores:

Código (dos) [Seleccionar]

@Echo OFF & (CHCP 1252)1>&2>NUL

Set "exeName=openvpn-gui"

:Loop
(TaskList.exe /FI "IMAGENAME eq "%exeName%.exe"" | Find "%exeName%.exe")1>&2>NUL && (
   REM Escribir aquí las órdenes cuando el resultado es True.
   Echo:El proceso "%exeName%.exe" está activo.

) || (
   REM Escribir aquí las órdenes cuando el resultado es False.
   Echo:El proceso "%exeName%.exe" está inactivo.

)

(TimeOut /T 1 /NoBreak)1>&2>NUL
GoTo :Loop


Saludos








llAudioslavell

Cita de: Eleкtro en 21 Septiembre 2016, 17:26 PM
Primero de nada, esto es un foro donde hay unas reglas de redacción, no importa la experiencia que tengas, si algo has de saber es formatear el código que publiques, usa las etiquetas GeShi.

Por favor, no pidas por mensajes privados que leamos tu post, por más que lo hagas yo no lo voy a leer antes ni después, sinó en su momento.

EDITO: También está prohibido hacer doble y triple post, USA EL BOTÓN MODIFICAR. Por favor, no me des más trabajo, escribe un post como Dios manda.




La variable %ERRORLEVEL% es un valor dinámico que cambia cada vez que termina la ejecución de un comando/executable, se asigna el código de salida a dicha variable dinámica.
No necesitas (ni tampoco podrías) crear una variable que cumpla su misma función, puedes reutilizar la variable %ERRORLEVEL% las veces que quieras, no se va a gastar :xD.




Batch es un lenguaje MUY limitado, simplemente no es posible reproducir una sentencia Else If de manera convencional, así que esa anidación de Ifs no te funcionará.

Batch está limitado a poder usar una sentencia If y un AND, y este último debemos usarlo de forma invisible...




Te aconsejo que modifiques ese código que has escrito, sigue la siguiente estructura y no tendrás por que tener errores:

Código (dos) [Seleccionar]

@Echo OFF & (CHCP 1252)1>&2>NUL

Set "exeName=openvpn-gui"

:Loop
(TaskList.exe /FI "IMAGENAME eq "%exeName%.exe"" | findstr "%exeName%.exe")1>&2>NUL && (
   REM Escribir aquí las órdenes cuando el resultado es True.
   Echo:El proceso "%exeName%.exe" está activo.

) || (
   REM Escribir aquí las órdenes cuando el resultado es False.
   Echo:El proceso "%exeName%.exe" está inactivo.

)

(TimeOut /T 1 /NoBreak)1>&2>NUL
GoTo :Loop


Saludos

Jaja disculpa las incomodidades !!
Entiendo que Batch sea limitado pero no pense que seria tan limitadi como para no funcionar un if anidado. En tal caso, como haria para poder evaluar otro proceso ??? En tu codigo estoy evaluando a openvpn-gui pero tambien necesito evaluar a openvpn  :(  :(  :( Se puede hacer en Batch?  :(

Eleкtro

#5
Se puede hacer, por supuesto, con una correcta anidación de Ifs (esto es, meter un If dentro de otro, nada de usar Else If, eso ya ha quedado claro que no es posible), pero queda muy feo.

Si quieres comprobar si ambos procesos se encuentran activos al mismo tiempo, para no enbrutecer demasiado el código resultante podrías hacerlo de la siguiente manera:

Código (dos) [Seleccionar]
@Echo OFF & (CHCP 1252)1>&2>NUL
SetLocal EnabledelayedExpansion

:Loop
Set /A "exitCodeCount=0"
(Call :CheckGUI) & (Set /A "exitCodeCount+=!ERRORLEVEL!")
(Call :CheckCLI) & (Set /A "exitCodeCount+=!ERRORLEVEL!")

If "!exitCodeCount!" EQU "0" (
    Echo:Ambos procesos están activos.

) Else (
    If "!exitCodeCount!" EQU "1" (
        Echo:Al menos uno de los procesos está inactivo.
   
    ) Else ( :: "!exitCodeCount!" EQU "2"
        Echo:Ninguno de los procesos está activo.
   
    )
   
)

(TimeOut /T 1 /NoBreak)1>&2>NUL
GoTo :Loop

:CheckGUI
(TaskList.exe /FI "IMAGENAME eq openvpn-gui.exe" | findstr "openvpn-gui.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"

:CheckCLI
(TaskList.exe /FI "IMAGENAME eq openvpn.exe" | findstr "openvpn.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"


Lo que hago es declarar una variable "exitCodeCount" que servirá para determinar si ambos procesos están activos basándose en la suma de los códigos de salida de las subrutinas "CheckGUI" y "CheckCLI", si ambas llamadas a "CheckGUI" y "CheckCLI" devuelven "0" (0+0) entonces significa que ambos están activos, si devuelve "1" (0+1), que uno de los procesos se encuentra inactivo, y si devuelve "2" (1+1) significa que ningún proceso está activo.

Saludos!








llAudioslavell

Cita de: Eleкtro en 21 Septiembre 2016, 17:49 PM
Se puede hacer, por supuesto, con una correcta anidación de Ifs (esto es, meter un If dentro de otro, nada de usar Else If, eso ya ha quedado claro que no es posible), pero queda muy feo.

Si quieres comprobar si ambos procesos se encuentran activos al mismo tiempo, para no enbrutecer demasiado el código resultante podrías hacerlo de la siguiente manera:

Código (dos) [Seleccionar]
@Echo OFF & (CHCP 1252)1>&2>NUL
SetLocal EnabledelayedExpansion

:Loop
Set /A "exitCodeCount=0"
(Call :CheckGUI) & (Set /A "exitCodeCount+=!ERRORLEVEL!")
(Call :CheckCLI) & (Set /A "exitCodeCount+=!ERRORLEVEL!")

If "!exitCodeCount!" EQU "0" (
    Echo:Ambos procesos están activos.

) Else (
    If "!exitCodeCount!" EQU "1" (
        Echo:Al menos uno de los procesos está inactivo.
   
    ) Else ( :: "!exitCodeCount!" EQU "2"
        Echo:Ninguno de los procesos está activo.
   
    )
   
)

(TimeOut /T 1 /NoBreak)1>&2>NUL
GoTo :Loop

:CheckGUI
(TaskList.exe /FI "IMAGENAME eq openvpn-gui.exe" | findstr "openvpn-gui.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"

:CheckCLI
(TaskList.exe /FI "IMAGENAME eq openvpn.exe" | findstr "openvpn.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"


Lo que hago es declarar una variable "exitCodeCount" que servirá para determinar si ambos procesos están activos basándose en la suma de los códigos de salida de las subrutinas "CheckGUI" y "CheckCLI", si ambas llamadas a "CheckGUI" y "CheckCLI" devuelven "0" (0+0) entonces significa que ambos están activos, si devuelve "1" (0+1), que uno de los procesos se encuentra inactivo, y si devuelve "2" (1+1) significa que ningún proceso está activo.

Saludos!

Muchas gracias amigo !!! pero el problemilla es que tengo que saber exactamente cual de los dos procesos esta abierto y/o esta cerrado :(

@echo off
:bucle

tasklist | findstr openvpn-gui.exe

set /a indOPENVPN= %ERRORLEVEL%

if %indOPENVPN% EQU 1 (
       echo.interfazClose
   tasklist | findstr openvpn.exe
   echo %ERRORLEVEL%
   if %ERRORLEVEL% EQU 1 (
      echo.conexionClose
   )else (
      echo.conexionOpen
   )

) else (
        echo.interfazOpen
)

goto bucle

Mira te explico, en mi codigo en el if anidado si esta entrando ! pero no entiendo porque ERRORLEVEL me arroga el valor 0 si el proceso esta cerrado pero cuando abro la conexion no me imprime ni 0 ni nada !  :(  :(  :(  :(

Eleкtro

#7
¿Qué hemos hablado de publicar correctamente un código?, modifica ese código y entonces te responderé... si no lo hace otra persona antes.

...de todas formas, en el último código que te mostré, tienes dos funciones que devuelven 0 o 1 (False o True) cada una dependiendo de si un programa y el otro se encuentran, eso debería bastarte para que puedas comprender como podrías adaptar el código a tus necesidades, es muy sencillo, lo único que necesitas hacer es comprobar el valor de la variable exitCodeCount (o %ERRORLEVEL%).

Saludos








llAudioslavell

Cita de: Eleкtro en 21 Septiembre 2016, 18:30 PM
¿Qué hemos hablado de publicar correctamente un código?, hazlo y entonces te responderé... si no lo hace otra persona antes.

Saludos

No se como hacerlo :'( con que opcion lo hago ?

Eleкtro

Cita de: llAudioslavell en 21 Septiembre 2016, 18:33 PMNo se como hacerlo :'( con que opcion lo hago ?

Con este:





En fin, te explico...

Tomando como base el código que mostré, puedes determinar de forma individual el estado de cada proceso de la siguiente manera:

Código (DOS) [Seleccionar]
@Echo OFF & (CHCP 1252)1>&2>NUL
SetLocal EnabledelayedExpansion

:Loop
Set /A "isGUIactive=-1"
Set /A "isCLIactive=-1"
(Call :CheckGUI) & (Set /A "isGUIactive=!ERRORLEVEL!")
(Call :CheckCLI) & (Set /A "isCLIactive=!ERRORLEVEL!")

If "!isGUIactive!" EQU "0" (
   Echo:El proceso "openvpn-gui" está activo.
)

If "!isCLIactive!" EQU "0" (
   Echo:El proceso "openvpn" está activo.
)

If "!isGUIactive!" EQU "0" If "!isCLIactive!" EQU "0" (
   Echo:Ambos procesos está activos.
)

(TimeOut /T 1 /NoBreak)1>&2>NUL
GoTo :Loop

:CheckGUI
(TaskList.exe /FI "IMAGENAME eq openvpn-gui.exe" | Find "openvpn-gui.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"

:CheckCLI
(TaskList.exe /FI "IMAGENAME eq openvpn.exe" | Find "openvpn.exe")1>&2>NUL
Exit /B "%ERRORLEVEL%"