Вывод в стандартный поток ошибок в Go
Привет, я бездарь.
Я не смог найти много статей, объясняющих эту часть для Go, поэтому я записываю это.
Проверка возвращаемого значения
Когда у нас был такой код изначально.
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)
}
Конечно, ошибки в Go будут выводиться как ошибки, как показано выше, но что, если мы хотим получить возвращаемое значение ошибки из исполняемого файла после сборки?
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
Все это обрабатывается как стандартный вывод.
Указание возвращаемого значения с помощью os.Exit
Поэтому нам нужно указать его с помощью os.Exit, чтобы он правильно обрабатывался как ошибка, и исправить его следующим образом.
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)
}
Теперь снова собираем и запускаем.
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
Возвращаемое значение было получено правильно.
Попробуем отбросить успешный шаблон с возвращаемым значением 0 в /dev/null
Мы можем отбросить только стандартный вывод с возвращаемым значением 0 с помощью > /dev/null, так что давайте попробуем это.
alleycat:[haturatu]:~/git/go-title$ ./go-title > /dev/null
alleycat:[haturatu]:~/git/go-title$ ./go-title http://https://soulminingrig.nodomain/ > /dev/null
В этом случае fmt.Println относится к стандартному выводу, поэтому сообщения об ошибках не будут видны.
Для большинства правильных GNU Tools и других исполняемых файлов не принято выводить сообщения об ошибках в стандартный вывод, поэтому сообщения об ошибках также должны выводиться в стандартный поток ошибок.
Даже в официальной документации все выводится с помощью fmt.Print, но
Возврат и обработка ошибки
https://pkg.go.dev/errors
Хотя в мире Go нет особой необходимости специально выводить в стандартный поток ошибок при создании модулей, это не соответствует потребности видеть только вывод ошибок при отладке с помощью > /dev/null.
В конце концов, здесь нужно использовать fprint, как и в C.
Далее, давайте передадим os.Stderr в качестве первого аргумента fprint для стандартного вывода ошибок.
Различия между fmt.Print и fmt.Fprint
Давайте изменим это следующим образом.
Эта статья очень понятна.
Как эффективно использовать функции семейства fmt.Print в Go
Если даже эта статья вызывает у вас недоумение, вы можете найти удовлетворительное объяснение, изучив различия в выводе функций семейства print в языке C.
Если вы не понимаете printf, вы можете попробовать с awk.
$ ls -la | awk '{print $9}'
$ ls -la | awk '{printf $9}'
fprint в awk... Я не знаю из-за недостатка знаний...
Если кто-то знает, пожалуйста, дайте мне знать.
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)
}
Теперь давайте посмотрим на результат.
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
Вывод ошибки был выполнен правильно.
Я действительно чувствую, что такого рода обработка легко вылетает из головы, поэтому нужно быть особенно осторожным с правильным выводом ошибок.