Работа с потоками stdin, stdout, stderr
Содержание:
Метод thread-safe
Первым фрагментом необходимого нам кода является класс, который мы можем использовать для того, чтобы вычленить пишущее API TextCtrl. Вот довольно стандартный пример.
Python
class RedirectText():
def __init__(self, my_text_ctrl):
self.out = my_text_ctrl
def write(self,string):
wx.CallAfter(self.out.WriteText, string)
1 |
classRedirectText() def__init__(self,my_text_ctrl) self.out=my_text_ctrl defwrite(self,string) wx.CallAfter(self.out.WriteText,string) |
Обратите внимание на то, что в данном классе используется лишь один метод (помимо метода инициализации, разумеется). Это позволяет нам записывать текст из stdout или stderr в текстовый контроль
Стоит отметить, что этот метод записи не является thread-safe. Если вам нужно перенаправить текст из thread, нужно немного видоизменить утверждение write следующим образом:
Python
def write(self, string):
wx.CallAfter(self.out.WriteText, string)
1 |
defwrite(self,string) wx.CallAfter(self.out.WriteText,string) |
Теперь, когда мы знаем, как записать stdout в TextCtrl, давайте попробуем самостоятельно написать немного кода, позволяющего собрать все части воедино. Вы также можете добавить следующий код в файл, содержащий класс, который был написан нами только что. Когда вы запустите код, то увидите приложение, которое выглядит примерно так:
Python
import sys
import wx
class RedirectText():
def __init__(self, my_text_ctrl):
self.out = my_text_ctrl
def write(self,string):
wx.CallAfter(self.out.WriteText, string)
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title=»wxPython Redirect Tutorial»)
# Добавляем панель, чтобы всё отображалось корректно на всех платформах
panel = wx.Panel(self, wx.ID_ANY)
log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,100),
style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
btn = wx.Button(panel, wx.ID_ANY, ‘Push me!’)
self.Bind(wx.EVT_BUTTON, self.onButton, btn)
# Добавляем виджеты на сайзер
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
# Перенаправленный текст отправляется сюда
redir = RedirectText(log)
sys.stdout = redir
def onButton(self, event):
print(«You pressed the button!»)
if __name__ == «__main__»:
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()
1 |
importsys importwx classRedirectText() def__init__(self,my_text_ctrl) self.out=my_text_ctrl defwrite(self,string) wx.CallAfter(self.out.WriteText,string) classMyForm(wx.Frame) def__init__(self) wx.Frame.__init__(self,None,title=»wxPython Redirect Tutorial») # Добавляем панель, чтобы всё отображалось корректно на всех платформах panel=wx.Panel(self,wx.ID_ANY) log=wx.TextCtrl(panel,wx.ID_ANY,size=(300,100), style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL) btn=wx.Button(panel,wx.ID_ANY,’Push me!’) self.Bind(wx.EVT_BUTTON,self.onButton,btn) # Добавляем виджеты на сайзер sizer=wx.BoxSizer(wx.VERTICAL) sizer.Add(log,1,wx.ALL|wx.EXPAND,5) sizer.Add(btn,,wx.ALL|wx.CENTER,5) panel.SetSizer(sizer) # Перенаправленный текст отправляется сюда redir=RedirectText(log) sys.stdout=redir defonButton(self,event) print(«You pressed the button!») if__name__==»__main__» app=wx.App(False) frame=MyForm().Show() app.MainLoop() |
В коде, расположенном вверху, я создал мультистрочный текстовый контроль, доступный только для чтения, и кнопку, главной задачей которой является вывод текста на stdout. Я добавил их в BoxSizer, чтобы защитить виджеты от напяливания друг поверх друга и для того, чтобы не возникало проблем с изменением размера рамки. Затем я инициирую класс RedirectText, пропуская его через инстанцию моего текстового контроля. Наконец, я настраиваю stdout в инстанцию RedirectText, redir (например, sys.stdout=redir).
Если вы хотите перенаправить stderr, просто добавьте следующую строку после sys.stdout=redir: sys.stderr=redir.
Вы можете улучшить данный пример изменив цвета кода, поступающего из stdout и stderr для того, чтобы быстро их различать. Эту задачу я оставил для вас, чтобы вы могли поупражняться.
The scanf() and printf() Functions
The int scanf(const char *format, …) function reads the input from the standard input stream stdin and scans that input according to the format provided.
The int printf(const char *format, …) function writes the output to the standard output stream stdout and produces the output according to the format provided.
The format can be a simple constant string, but you can specify %s, %d, %c, %f, etc., to print or read strings, integer, character or float respectively. There are many other formatting options available which can be used based on requirements. Let us now proceed with a simple example to understand the concepts better −
#include <stdio.h> int main( ) { char str; int i; printf( "Enter a value :"); scanf("%s %d", str, &i); printf( "\nYou entered: %s %d ", str, i); return 0; }
When the above code is compiled and executed, it waits for you to input some text. When you enter a text and press enter, then program proceeds and reads the input and displays it as follows −
$./a.out Enter a value : seven 7 You entered: seven 7
Here, it should be noted that scanf() expects input in the same format as you provided %s and %d, which means you have to provide valid inputs like «string integer». If you provide «string string» or «integer integer», then it will be assumed as wrong input. Secondly, while reading a string, scanf() stops reading as soon as it encounters a space, so «this is test» are three strings for scanf().
Previous Page
Print Page
Next Page
Перенаправление ошибок
Иногда, когда вы запускаете какую-либо команду или скрипт, вы видите, что на экране отображается сообщение об ошибке.
andreyex@destroyer:~$ ls -l ffffff > output.txt ls: cannot access 'ffffff': No such file or directory
В начале этой статьи мы упоминали, что существует три потока данных, и stderr – это один из потоков выходных данных, который отображается на экране по умолчанию.
Вы также можете перенаправить stderr. Поскольку это поток выходных данных, вы можете использовать тот же символ перенаправления > или >>, который вы использовали для перенаправления стандартного вывода.
Но как вы различаете stdout и stderr, когда они оба являются потоком выходных данных? По их идентификатору потока (также называется дескриптором файла).
Поток данных | Идентификатор потока |
stdin | |
stdout | 1 |
stderr | 2 |
По умолчанию, когда вы используете выходной символ перенаправления >, это фактически означает 1>. Словом, вы говорите, что здесь выводится поток данных с ID 1.
Когда вам нужно перенаправить stderr, вы используете его идентификатор как 2> или 2>>. Это означает, что перенаправление вывода для потока данных stderr (ID 2).
Примеры перенаправления Stderr
Позвольте нам показать вам несколько примеров. Предположим, вы просто хотите сохранить ошибку, вы можете использовать что-то вроде этого:
andreyex@destroyer:~$ ls fffff 2> error.txt andreyex@destroyer:~$ cat error.txt ls: cannot access 'fffff': No such file or directory
Это было просто. Давайте сделаем это немного более сложным (и полезным):
andreyex@destroyer:~$ ls -l new.txt ffff > output.txt 2> error.txt andreyex@destroyer:~$ cat output.txt -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt andreyex@destroyer:~$ cat error.txt ls: cannot access 'ffff': No such file or directory
В приведенном выше примере команда ls пытается отобразить два файла. Для одного файла она получает успех, а для другого – ошибку. Поэтому мы перенаправили stdout в ouput.txt (с>), а stderr в error.txt (с 2>).
Вы также можете перенаправить как stdout, так и stderr в один и тот же файл. Есть способы сделать это.
В приведенном ниже примере мы сначала отправляем stderr (с 2 >>) в файл комбинированный .txt в режиме добавления. Затем стандартный вывод (с >>) отправляется в тот же файл в режиме добавления.
andreyex@destroyer:~$ ls -l new.txt fff 2>> combined.txt >> combined.txt andreyex@destroyer:~$ cat combined.txt ls: cannot access 'fff': No such file or directory -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt
Другой способ, и он является предпочтительным, состоит в том, чтобы использовать что-то вроде 2>&1. Что можно примерно перевести как «перенаправить stderr на тот же адрес, что и stdout».
Давайте возьмем предыдущий пример и на этот раз используем 2>&1 для перенаправления как stdout, так и stderr в один и тот же файл.
andreyex@destroyer:~$ ls -l new.txt fff > output.txt 2>&1 andreyex@destroyer:~$ cat output.txt ls: cannot access 'fff': No such file or directory -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt
Имейте в виду, что вы не можете использовать 2>>&1, думая об использовании его в режиме добавления. 2>&1 уже переходит в режим добавления.
Вы также можете сначала использовать 2>, а затем 1>&2, чтобы перенаправить стандартный вывод в тот же файл, что и стандартный вывод. По сути, это «>&», который перенаправляет один поток данных в другой.
Резюме
- Есть три потока данных. Один вход, stdin (0) и два потока выходных данных stdout (1) и stderr (2).
- Клавиатура является стандартным устройством ввода, а экран является устройством вывода по умолчанию.
- Перенаправление вывода используется с > или >> (для режима добавления).
- Перенаправление ввода используется с <.
- Stderr может быть перенаправлен с помощью 2> или 2>>.
- Stderr и stdout можно комбинировать, используя 2>&1.
3. sys.stderr
This is similar to because it also prints directly to the Console. But the difference is that it only prints Exceptions and Error messages. (Which is why it is called Standard Error).
Let us illustrate this with an example.
import sys stdout_fileno = sys.stdout stderr_fileno = sys.stderr sample_input = for ip in sample_input: # Prints to stdout stdout_fileno.write(ip + '\n') # Tries to add an Integer with string. Raises an exception try: ip = ip + 100 # Catch all exceptions except: stderr_fileno.write('Exception Occurred!\n')
Output
Hi Exception Occurred! Hello from AskPython Exception Occurred! exit Exception Occurred!
As you can observe, for all the input strings, we try to add to an Integer, which will raise an Exception. We catch all such exceptions and print another debug message using .
Redirection to a file
We can redirect the , and file handles to any other file (file-handle). This may be useful if you want to log events to a file without using any other module such as Logging.
The below snippet redirects output() to a file called .
So, we will not see anything printed to the Console, because it is now being printed to the file itself! This is the essence of Output redirection. You ‘redirect’ the Output to some other place. (This time, to , instead of the Console)
import sys # Save the current stdout so that we can revert sys.stdou after we complete # our redirection stdout_fileno = sys.stdout sample_input = # Redirect sys.stdout to the file sys.stdout = open('Output.txt', 'w') for ip in sample_input: # Prints to the redirected stdout (Output.txt) sys.stdout.write(ip + '\n') # Prints to the actual saved stdout handler stdout_fileno.write(ip + '\n') # Close the file sys.stdout.close() # Restore sys.stdout to our old saved file handler sys.stdout = stdout_fileno
Output
root@ubuntu:~# python3 output_redirection.py Hi Hello from AskPython exit root@ubuntu:~# cat Output.txt Hi Hello from AskPython exit
As you can see, we have printed the output to both the Console, as well as to .
We first save the original file handler object to another Variable. We not only need this to restore to the old handler (pointing to the Console), but we can also print to the console using this Variable!
Note that after writing to the file, we close it, similar to how we close a file because that file was still open.
We finally restore the handler of to the Console, using the variable .
A similar process can be followed for Input and Error redirection, replacing with or and working with Inputs and Exceptions instead of Output.
Виды потоков
В системах Linux и Unix существуют стандартные входной (STDIN) и выходные (STDOUT, STDERR) потоки (каналы). Далее рассмотрим подробнее каждый из них.
- STDIN (Номер файлового дескриптора — 0)Стандартный входной поток. Канал принимающий данные для обработки и последующей передачи на канал STDOUT и/или STDERR.
- STDOUT (Номер файлового дескриптора — 1)Стандартный выходной поток. Представляет собой канал записи результатов выполнения каких-либо процессов.
- STDERR (Номер файлового дескриптора — 2)Стандартный выходной поток ошибок. В данный канал попадают сообщения об ошибках.
В рамках терминала канал STDIN считывает входные данные, а каналы STDOUT и STDERR выводят выходные данные на экран.
NOTES top
The stream stderr is unbuffered. The stream stdout is line-buffered when it points to a terminal. Partial lines will not appear until fflush(3) or exit(3) is called, or a newline is printed. This can produce unexpected results, especially with debugging output. The buffering mode of the standard streams (or any other stream) can be changed using the setbuf(3) or setvbuf(3) call. Note that in case stdin is associated with a terminal, there may also be input buffering in the terminal driver, entirely unrelated to stdio buffering. (Indeed, normally terminal input is line buffered in the kernel.) This kernel input handling can be modified using calls like tcsetattr(3); see also stty(1), and termios(3).