Saltar al contenido

$LastExitCode=0, pero $?=False en PowerShell. Redirigir stderr a stdout da NativeCommandError

Revisamos exhaustivamente cada una de las noticias de nuestro sitio web con el objetivo de enseñarte siempre la información con la mayor veracidad y certera.

Solución:

(Estoy usando PowerShell v2.)

Los ‘$?‘ variable está documentada en about_Automatic_Variables:

$?
  Contains the execution status of the last operation

Esto se refiere a la operación de PowerShell más reciente, a diferencia del último comando externo, que es lo que obtienes $LastExitCode.

En tu ejemplo, $LastExitCode es 0, porque el último comando externo fue cmdque era exitoso en hacer eco de algún texto. Pero el 2>&1 hace que los mensajes stderr para convertirse en registros de error en el flujo de salida, lo que le dice a PowerShell que hubo un error durante la última operacióncausando $? ser False.

Para ilustrar esto un poco más, considere esto:

> java -jar foo; $?; $LastExitCode
Unable to access jarfile foo
False
1

$LastExitCode es 1, porque ese era el código de salida de java.exe. $? es falso, porque lo último que hizo el shell falló.

Pero si todo lo que hago es cambiarlos:

> java -jar foo; $LastExitCode; $?
Unable to access jarfile foo
1
True

… luego $? es cierto, porque lo último que hizo el shell fue imprimir $LastExitCode al anfitrión, que tuvo éxito.

Finalmente:

> & java -jar foo ; $?; $LastExitCode
Unable to access jarfile foo
True
1

…lo que parece un poco contrario a la intuición, pero $? es Cierto ahora, porque la ejecución del bloque de script fue exitosoincluso si el comando que se ejecuta dentro de él no lo fue.


volviendo a la 2>&1 redirigir…. eso hace que un registro de error vaya en el flujo de salida, que es lo que da ese blob prolijo sobre el NativeCommandError. El shell está descargando todo el registro de errores.

Esto puede ser especialmente molesto cuando todo lo que quiere hacer es canalizar stderrystdout juntos para que puedan combinarse en un archivo de registro o algo así. ¿Quién quiere que PowerShell se meta en su archivo de registro? Si lo hago ant build 2>&1 >build.logentonces cualquier error que vaya a stderr tener PowerShell curioso Se agregaron $ 0.02, en lugar de obtener mensajes de error limpios en mi archivo de registro.

Pero, el flujo de salida no es un texto ¡Arroyo! Los redireccionamientos son solo otra sintaxis para el objeto tubería. Los registros de errores son objetos, por lo que todo lo que tiene que hacer es convertir los objetos en ese flujo a instrumentos de cuerda antes de redirigir:

Desde:

> cmd /c "echo Hello from standard error 1>&2" 2>&1
cmd.exe : Hello from standard error
At line:1 char:4
+ cmd &2" 2>&1
    + CategoryInfo          : NotSpecified: (Hello from standard error :String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Para:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | % "$_" 
Hello from standard error

…y con una redirección a un archivo:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | % "$_"  | tee out.txt
Hello from standard error

…o solo:

> cmd /c "echo Hello from standard error 1>&2" 2>&1 | % "$_"  >out.txt

Este error es una consecuencia imprevista del diseño prescriptivo de PowerShell para el manejo de errores, por lo que lo más probable es que nunca se solucione. Si su secuencia de comandos solo se reproduce con otras secuencias de comandos de PowerShell, está a salvo. Sin embargo, si su secuencia de comandos interactúa con aplicaciones del gran mundo, este error puede picar.

PS> nslookup microsoft.com 2>&1 ; echo $?

False

¡Entendido! Aún así, después de un doloroso rascado, nunca olvidarás la lección.

Utilizar ($LastExitCode -eq 0) en lugar de $?

(Nota: esto es principalmente especulación; rara vez uso muchos comandos nativos en PowerShell y otros probablemente sepan más sobre los componentes internos de PowerShell que yo)

Supongo que encontró una discrepancia en el host de la consola de PowerShell.

  1. Si PowerShell recoge cosas en el flujo de error estándar, asumirá un error y generará un NativeCommandError.
  2. PowerShell solo puede detectar esto si monitores el flujo de error estándar.
  3. ISE de PowerShell tiene que supervíselo, porque no es una aplicación de consola y, por lo tanto, una aplicación de consola nativa no tiene una consola en la que escribir. Esta es la razón por la que en PowerShell ISE esto falla independientemente de la 2>&1 operador de redirección
  4. El anfitrión de la consola voluntad monitorear el flujo de error estándar si usa el 2>&1 operador de redirección porque la salida en el flujo de error estándar debe redirigirse y, por lo tanto, leerse.

Mi conjetura aquí es que el host de PowerShell de la consola es perezoso y solo entrega los comandos nativos de la consola a la consola si no necesita realizar ningún procesamiento en su salida.

Realmente creo que esto es un error, porque PowerShell se comporta de manera diferente según la aplicación host.

Aquí tienes las comentarios y valoraciones

Si posees alguna suspicacia y disposición de avanzar nuestro post eres capaz de dejar una nota y con placer lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *