Перенаправить панику stderr обратно на терминал в го - PullRequest
0 голосов
/ 30 декабря 2018

Я пытаюсь перенаправить панику / стандартную ошибку обратно в терминал bash с помощью следующего кода:

    if err := syscall.Dup2(-1,int(os.Stderr.Fd())); err != nil {
      log.Fatalf("Failed to redirect stderr to bash: %v",err)
    }

Но ошибка дает мне «плохой дескриптор файла», возможно, из-за -1 Я использовал в первом аргументе.Я выбрал значение -1, потому что обнаружил, что int(file.(*os.File).Fd()) вернул -1 при вызове file.Close().

Что касается того, что я пытаюсь сделать.В другом месте моей программы я назвал syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())), который записывает stderr во внешний файл.Но я хочу, чтобы stderr иногда указывал на терминал bash.

https://golang.org/pkg/syscall/ Не дает подробного объяснения syscall.Dup2.Я начал выяснять, что file.Fd () возвращает и как он используется, но также не совсем понял.

Может кто-нибудь сказать мне, как перенаправить stderr обратно в терминал bash?

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Вы должны сохранить оригинальный stderr где-нибудь перед тем, как перезаписать его первым Dup2.(В общем, плохая идея использовать функцию dup2 закрытия цели, поскольку она не может сообщать об ошибках оттуда.) Затем вы можете Dup2 , что вернуться к int(os.Stderr.Fd()) (иначе2).

0 голосов
/ 30 декабря 2018

Может кто-нибудь сказать мне, как перенаправить stderr обратно на терминал bash?

В общем, это невозможно , потому что может быть запущена программа Unix (илизапустить) без любого терминала.Например, он может быть запущен заданием crontab (5) или какой-либо командой at или ssh и т. Д. Также подумайте о том, что ваша программа запускается с перенаправлениями или в конвейере , или если ваша программа запущена на сервере (например, внутри центра обработки данных);тогда он, скорее всего, не будет иметь никакого терминала.

Обычная практика заключается в том, что пользователь вашей программы, возможно, перенаправляет stderr (и, вероятно, не на терминал, но с большей вероятностьюкакой-то файл).Ваш пользователь будет использовать для этой цели shell (например, запустите yourprogram 2> /tmp/errorfile; прочитайте документацию bash о перенаправлениях )

Terminals довольно сложные вещи.Вы можете прочитать страницу демовертированного TTY .См. Также pty (7) и termios (3) .Обычный способ обработки терминалов (в Unix) - использование библиотеки ncurses (которая была обернута в goncurses в Go).

В другом месте вмоя программа, я назвал syscall.Dup2 (int (file.Fd ()), int (os.Stderr.Fd ())), который записывает stderr во внешний файл.

Это действительно плохая идея.Ваш пользователь ожидает, что его / ее stderr останется прежним (и перенаправил бы stderr в его / ее оболочке, если это необходимо).Традиционно, вы не должны путать стандартных потоков в вашей программе (и оставить их такими, какие они есть).

A дескриптор файла - это небольшой положительный илинулевой индекс (в таблицу дескрипторов файлов вашего процесса ).Системные вызовы, такие как dup2 (2) , ожидают допустимые файловые дескрипторы, а Go syscall.Dup2 просто оборачивает это dup2 (2) .

В Linux вы можетезапросить таблицу дескрипторов файлов какого-либо процесса pid 1234, заглянув в каталог /proc/1234/fd/.См. proc (5) для получения дополнительной информации.

Если вы абсолютно уверены, что ваша программа работает в терминале, вы можете открыть /dev/tty, чтобы получить ее.Смотрите tty (4) для получения дополнительной информации.Однако я не рекомендую делать это (потому что вы лучше спроектируете свою программу так, чтобы она работала вне любого терминала).

Возможно, вы захотите прочитать какую-нибудь книгу по программированию Linux, напримерas ALP .

Для целей ведения журнала Go предоставляет пакет log .См. Также syslog (3) и log/syslog пакет Go.

PS.Я не знаю Windows, но я считаю, что она также может запускать программы без терминала, например, фоновый процесс .Поэтому даже в Windows я бы старался избегать этого (перенаправление stderr на терминал).

0 голосов
/ 30 декабря 2018

Я не знаю почему, но syscall.Dup2(0,int(os.Stderr.Fd())) возвращает панику stderr обратно в терминал.

Мое понимание операционной системы linux слабое.Поэтому я не понимаю значения 0 в этом контексте и документации linux.

Кроме того, я не пробовал этот подход на машине с Windows, поэтому не уверен, что там произойдет.Я надеюсь, что другие люди дают лучшие ответы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...