En Go: Al redirigir a la salida de error estándar
Hola, soy un inútil.
No encontré muchos artículos que explicaran esta parte en el caso de Go, así que lo anoto.
Verificar el valor de retorno
Inicialmente, cuando teníamos un código como este:
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go https://soulminingrig.com/")
return
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Printf( "Error: %v\n", err)
return
}
fmt.Printf("Title: %s\n", title)
}
Por supuesto, incluso con el código anterior, lo que se convierte en error en Go se emite como error, pero ¿qué pasaría si quisiéramos obtener el valor de retorno de un error de un binario ejecutable después de la compilación?
alleycat:[haturatu]:~/git/go-title$ ./go-title
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
0
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
0
Todo se trata como salida estándar.
Especificar el valor de retorno con os.Exit
Por lo tanto, para que se trate correctamente como un error, es necesario especificarlo con os.Exit, así que lo corregimos de la siguiente manera:
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go https://soulminingrig.com/")
os.Exit(1)
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Printf( "Error: %v\n", err)
os.Exit(2)
}
fmt.Printf("Title: %s\n", title)
}
Con esto, volvemos a compilar y ejecutar.
alleycat:[haturatu]:~/git/go-title$ ./go-title
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
1
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
2
El valor de retorno fue devuelto correctamente.
Intentar descartar el patrón de éxito con valor de retorno 0 en /dev/null
Con > /dev/null, se puede descartar solo la salida estándar con valor de retorno 0, así que intentémoslo.
alleycat:[haturatu]:~/git/go-title$ ./go-title > /dev/null
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/ > /dev/null
En este caso, sin embargo, fmt.Println corresponde a la salida estándar, por lo que no se pueden ver los mensajes de error.
La mayoría de las GNU Tools correctas y otros binarios ejecutables no suelen emitir mensajes de error a la salida estándar, por lo que los mensajes de error también deben emitirse a la salida de error.
Incluso en la documentación oficial, solo se muestran ejemplos que usan fmt.Print
Return and handle an error
https://pkg.go.dev/errors
Si solo se crean módulos dentro del mundo de Go, no hay mucha necesidad de forzar la salida de error estándar, pero no satisface la necesidad de ver solo la salida de error al depurar usando solo > /dev/null.
En última instancia, aquí, al igual que en C, es necesario manejarlo con fprint.
A continuación, intentemos pasar os.Stderr como salida de error estándar al primer argumento de fprint.
Diferencia entre fmt.Print y fmt.Fprint
Intentemos cambiarlo de la siguiente manera.
Este artículo es muy fácil de entender.
Go の fmt.Print 系関数は上手に使い分けたい
Si incluso con este artículo te preguntas '¡¿qué es esto?!', si investigas las diferencias en la salida de las funciones print de C, podrías encontrar algo que te convenza.
Si no entiendes printf, puedes probarlo con awk.
$ ls -la | awk '{print $9}'
$ ls -la | awk '{printf $9}'
fprint en awk es... . No lo sé por falta de conocimiento... .
Si alguien lo sabe, me gustaría que me lo dijera.
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Usage: go run main.go https://soulminingrig.com/")
os.Exit(1)
}
url := os.Args[1]
title, err := fetchTitle(url)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(2)
}
fmt.Printf("Title: %s\n", title)
}
Con esto, veamos el resultado.
alleycat:[haturatu]:~/git/go-title$ ./go-title > /dev/null
Usage: go run main.go https://soulminingrig.com/
alleycat:[haturatu]:~/git/go-title$ echo $?
1
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/ > /dev/null
Error: failed to fetch URL: Get "http://https//soulminingrig.nodomain/": dial tcp: lookup https: no such host
alleycat:[haturatu]:~/git/go-title$ echo $?
2
La salida de error se realizó correctamente.
Realmente, este tipo de manejo es fácil de olvidar, así que sentí profundamente que hay que tener especial cuidado al manejar la salida de error correcta.