Basic usage
In Python, the , , and are file-like objects that can perform
expected operations like and . Let’s look at how to use these objects.
Refer to the official sys package documentation for full information.
Standard output
Standard output
is basically a shortcut for
is a objects so you can read and write to them like a regular file.
See for more details about the class.
To pipe the output of your Python program to a file, you can do it from the shell like this:
Standard error
Standard error works just like standard output and can be used the same way. Standard error has file descriptor where standard output has file descriptor . This is beneficial if you want to separate warning and error messages from the actual output of your application. For example, if your program outputs an XML file, you don’t want error strings injected in the middle of your XML file.
To pipe standard error from the shell to a file while leaving standard output going to the terminal:
To pipe standard error in to standard output, you can do:
Standard input
Standard input defaults to your keyboard in the terminal, but you can also pipe in files
or the output from a previous program to your standard input. Here is a basic example
of reading one byte from standard input:
If you want interactive input from the user, it is better to use instead of when asking for user input,
but can be useful for reading a file that was piped in from the shell like this:
To pipe the standard output of one program to the standard input of your Python program,
you can do it like this:
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).
Выбор текста
Нам понадобится текстовый файл для наших примеров. Мы будем использовать тот, который содержит подборку стихов из эпической поэмы Сэмюэля Тейлора Кольриджа «Изморозь древнего моряка».
Мы набираем следующее, чтобы взглянуть на это с :
less coleridge.txt
Чтобы выбрать некоторые строки из файла, мы предоставляем начальную и конечную строки диапазона, который мы хотим выбрать. Одно число выбирает эту строку.
Чтобы извлечь строки от одной до четырех, мы набираем эту команду:
sed -n '1,4p' coleridge.txt
Обратите внимание на запятую между и , означает «печать совпавших строк». По умолчанию, печатает все строки
Мы увидим весь текст в файле с совпадающими строками, напечатанными дважды. Чтобы предотвратить это, мы будем использовать (тихий) вариант для подавления несогласованного текста.
Мы изменили номера строк, чтобы мы могли выбрать другой стих, как показано ниже:
sed -n '6,9p' coleridge.txt
Мы можем использовать (выражение) вариант, чтобы сделать несколько выборов. С двумя выражениями мы можем выбрать два стиха, например так:
sed -n -e '1,4p' -e '31,34p' coleridge.txt
Если мы уменьшим первое число во втором выражении, мы можем вставить пробел между двумя стихами. Мы вводим следующее:
sed -n -e '1,4p' -e '30,34p' coleridge.txt
Мы также можем выбрать стартовую линию и сказать пошагово просматривать файл и печатать чередующиеся строки, каждую пятую строку или пропускать любое количество строк. Команда похожа на те, которые мы использовали выше, чтобы выбрать диапазон. На этот раз, однако, мы будем использовать тильду () вместо запятой разделять цифры.
Первое число указывает на начальную строку. Второй номер говорит какие строки после стартовой линии мы хотим видеть. Число 2 означает каждую вторую строку, 3 означает каждую третью строку и т. Д.
Мы вводим следующее:
sed -n '1~2p' coleridge.txt
Вы не всегда будете знать, где находится искомый текст в файле, а это означает, что номера строк не всегда помогут. Тем не менее, вы также можете использовать выбрать строки, содержащие соответствующие текстовые шаблоны. Например, давайте извлечем все строки, начинающиеся с «И».
Каретка () представляет начало строки. Мы заключим наш поисковый запрос в косую черту (). Мы также добавляем пробел после «И», чтобы такие слова, как «Android», не были включены в результат.
чтение поначалу скрипты могут быть немного сложными. означает «печать», как это было в командах, которые мы использовали выше. Однако в следующей команде перед ним стоит косая черта:
sed -n '/^And /p' coleridge.txt
Три строки, начинающиеся с «И», извлекаются из файла и отображаются для нас.
Метод 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 следующим образом:
Стоит отметить, что этот метод записи не является 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 для того, чтобы быстро их различать. Эту задачу я оставил для вас, чтобы вы могли поупражняться.
Управление потоками
Для перенаправления каналов в терминале, применяют определенные символы. Рассмотрим каждый из них на примере команды поиска системных файлов, которые содержат слово — core. Все найденные файлы будут формироваться в поток STDOUT. Те найденные файлы, к которым у обычного пользователя нет доступа будут попадать в STDERR.
> — вывод STDOUT в файл.
В файл попадет список путей ко всем найденным файлам, а список ошибок отобразится в терминале.
Запись STDOUT в файл
Символ — затирает все его содержимое и вставляет значение из потока, поэтому будьте осторожны при правке системных файлов используя данный символ. Если Вам нужно добавить данные в конец файла — используйте два последовательных символа — .
>> — вывод STDOUT в конец файла.
В конец файла попадет список путей ко всем найденным файлам, а список ошибок отобразится в терминале.
Запись STDOUT в конец файла
>& — вывод STDOUT и STDERR в файл
С помощью составного символа — мы объединяем стандартный выходной поток с выходным потоком ошибок. В файл попадет список путей ко всем найденным файлам и список ошибок.
Объединение выходных потоков
2> — вывод STDERR в файл
В файл попадет список ошибок, а список найденных файлов, будет выведен в терминале.
Вывод STDERR
Вывод потоков можно комбинировать и распределять по разным местам. Например, выведем список найденных файлов в , а список ошибок отбросим, перенаправив их в .
Перенаправление потоков
Для того чтобы направить выходной поток одной команды на входной поток другой, применяют символ — (pipe).
Для примера, выведем в консоли отдельные процессы системы с именем — .
Здесь результат выполнения команды передается в роли входных данных для команды , в которых она ищет совпадения с именем .
STDOUT
STDOUT— стандартный поток вывода оболочки. По умолчанию это — экран. Большинство bash-команд выводят данные в
STDOUT, что приводит к их появлению в консоли. Данные можно перенаправить в файл, присоединяя их к его содержимому, для этого служит команда
>>.
Итак, у нас есть некий файл с данными, к которому мы можем добавить другие данные с помощью этой команды:
pwd >> myfile
1 | pwd>>myfile |
То, что выведет
pwd, будет добавлено к файлу
myfile, при этом уже имеющиеся в нём данные никуда не денутся.
Перенаправление вывода команды в файл
Пока всё хорошо, но что если попытаться выполнить что-то вроде показанного ниже, обратившись к несуществующему файлу
xfile, задумывая всё это для того, чтобы в файл
myfile попало сообщение об ошибке.
ls –l xfile > myfile
1 | ls–lxfile>myfile |
После выполнения этой команды мы увидим сообщения об ошибках на экране.
Попытка обращения к несуществующему файлу
При попытке обращения к несуществующему файлу генерируется ошибка, но оболочка не перенаправила сообщения об ошибках в файл, выведя их на экран. Но мы-то хотели, чтобы сообщения об ошибках попали в файл. Что делать? Ответ прост — воспользоваться третьим стандартным дескриптором.
Стандартный ввод (stdin) [ править ]
Стандартный ввод — это поток, из которого программа считывает свои входные данные. Программа запрашивает передачу данных с помощью операции чтения . Не все программы требуют потокового ввода. Например, программы dir и ls (которые отображают имена файлов, содержащихся в каталоге) могут принимать аргументы командной строки , но выполнять свои операции без ввода каких-либо потоковых данных.
Если не перенаправить , стандартный ввод наследуется от родительского процесса. В случае интерактивной оболочки это обычно связано с клавиатурой .
Дескриптор файла для стандартного ввода равен 0 (ноль); POSIX <unistd.h> определение ; соответствующая переменная C <stdio.h> : аналогично, переменная C ++ <iostream> имеет вид .
Перенаправление разных потоков
Файловый дескриптор (FD) — абстрактный индикатор (дескриптор), используемый для доступа к файлу или другому ресурсу ввода/вывода, например к каналу или сетевому сокету. Файловые дескрипторы являются частью POSIX API. Дескриптор файла является неотрицательным целым числом, обычно представленным на языке программирования C как тип int. Мы это рассмотрим позднее, когда будем программировать на C.
Каждый процесс UNIX (кроме демонов) должен иметь три стандартных файловых дескриптора (0, 1, 2), соответствующих трём стандартным потокам:
- stdin — стандартный ввод
- stdout — стандартный вывод
- stderr — стандартный вывод ошибок
В командной оболочке sh можно указывать номер потока (файловый дескриптор) непосредственно перед символом перенаправления.
К примеру:
команда1 2> файл1
выполняет команду1, направляя стандартный поток ошибок в файл1.
Часто стандартный поток ошибок объединяют со стандартным потоком вывода, чтобы можно было обрабатывать ошибки и обычные результаты работы программы вместе. К примеру:
find / -name .profile > results.txt 2>&1
попытается найти все файлы с именем .profile. Если выполнять эту команду без перенаправлений, она будет направлять результаты поиска в stdout, а сообщения об ошибках (к примеру, о недостаточности прав доступа при попытке поиска в защищённых каталогах) в stderr. По умолчанию обе эти роли выполняет консоль. Если стандартный поток вывода направлен в файл results.txt, то ошибки по-прежнему будут направляться в консоль. Чтобы и ошибки, и результаты поиска направлялись в файл results.txt, стандартные потоки ошибок и вывода были объединены с использованием 2>&1.
Написание 2>&1 перед > не будет работать, так как когда интерпретатор прочитает 2>&1, он ещё не знает, куда перенаправлен стандартный поток вывода, поэтому потоки ошибок и вывода не будут объединены.
Обнаружение перенаправления в скрипте
Мы обсудили, как команда может определить, перенаправляется ли один из потоков, и соответствующим образом изменить свое поведение. Можем ли мы добиться этого в наших собственных сценариях? Да мы можем. И это очень простой метод для понимания и использования.
Введите следующий текст в редактор и сохраните его как input.sh.
#! / bin / bash если ; затем echo stdin, поступающий с клавиатуры, иначе echo stdin, исходящий из канала или файла fi
Используйте следующую команду, чтобы сделать его исполняемым:
chmod + x input.sh
Умная часть — это тест в квадратных скобках. Опция (Терминал) возвращает истину (0), если файл связан с файловым дескриптором заканчивается в окне терминала. Мы использовали файловый дескриптор 0 в качестве аргумента теста, который .
Когда подключенный к окну терминала, тест подтвердится. если подключен к файлу или каналу, тест не пройден.
Мы можем использовать любой текстовый файл для генерации ввода для скрипта. Здесь мы используем файл dummy.txt.
./input.sh <dummy.txt
Выходные данные показывают, что сценарий распознает, что ввод идет не с клавиатуры, а из файла. При желании вы можете соответствующим образом изменить поведение вашего скрипта.
Это было с перенаправлением файлов, давайте попробуем канал.
кот dummy.txt | ./input.sh
Сценарий распознает, что его ввод передается по конвейеру. Или, точнее, еще раз признает, что поток не подключен к окну терминала.
Запустим скрипт без каналов и редиректов.
./input.sh
Умереть поток подключен к окну терминала, и сценарий сообщает об этом соответственно.
Чтобы проверить то же самое с выходным потоком, нам понадобится новый скрипт. Введите следующее в редактор и сохраните как output.sh.
#! / bin / bash если ; тогда echo stdout переходит в окно терминала, иначе echo stdout перенаправляется или передается по каналу fi
Используйте следующую команду, чтобы сделать его исполняемым:
chmod + x input.sh
Единственное существенное изменение в этом скрипте — тест в квадратных скобках. Мы используем цифру 1 для обозначения файлового дескриптора. представлять .
Давай попробуем. Мы пропускаем вывод через .
./output | Кот
Сценарий распознает, что его вывод не попадает непосредственно в окно терминала.
Мы также можем протестировать сценарий, перенаправив вывод в файл.
./output.sh> capture.txt
В окне терминала нет вывода, молча возвращаемся в командную строку. Как и следовало ожидать.
Мы можем заглянуть в файл capture.txt, чтобы увидеть, что было захвачено. Для этого используйте следующую команду.
кошка capture.sh
Опять же, простой тест в нашем скрипте распознает, что поток не отправляется непосредственно в окно терминала.
Если мы запустим скрипт без каналов или перенаправлений, он должен распознать это. доставляется прямо в окно терминала.
./output.sh
И это именно то, что мы видим.
Перенаправление канала
Прежде чем вы увидите перенаправление stdin, вы должны узнать о перенаправлении канала. Это более распространено, и, вероятно, вы будете часто его использовать.
При перенаправлении канала стандартный вывод команды отправляется на стандартный ввод другой команды.
command 1 | command 2
Позвольте нам показать вам практический пример. Скажем, вы хотите посчитать количество видимых файлов в текущем каталоге. Вы можете использовать ls -1 (это цифра один, а не буква L) для отображения файлов в текущем каталоге:
andreyex@destroyer:~$ ls -1 appstxt new.txt output.txt static-ip.txt
Вы, наверное, уже знаете, что команда wc используется для подсчета количества строк в файле . Если вы объедините обе эти команды с конвейером, вот что вы получите:
andreyex@destroyer:~$ ls -1 | wc -l 4
При использовании pipe обе команды совместно используют один и тот же буфер памяти. Вывод первой команды сохраняется в буфере, и этот же буфер затем используется в качестве ввода для следующей команды.
Вы увидите результат последней команды в конвейере. Это очевидно, потому что вывод предыдущей команды (команд) подается на следующую команду (команды) вместо перехода на экран.
Перенаправление трубы или трубопровод не ограничиваются соединением только двух команд. Вы можете подключить больше команд, если выходные данные одной команды могут использоваться как входные данные следующей команды.
command_1 | command_2 | command_3 | command_4
Другие примеры
Следующий пример показывает, почему иногда очень полезно разделять потоки из каналов STDIN и STDERR:
$ find / -name core 2> /dev/null
Дело в том, что команда find / -name core будет «сыпать» сообщениями об ошибках, направляя их по-умолчанию в то же место, что и результаты поиска. Т. е. в терминал командной консоли, что существенно затруднит восприятие информации пользователем. Т. к. искомые результаты затеряются среди многочисленных сообщений об ошибках, связанных с режимом доступа. Конструкция 2>/dev/null заставляет утилиту find отправлять сообщения об ошибках (следующие по каналу STDERR с зарезервированным номером 2) на фиктивное устройство /dev/null, оставляя в выводе только результаты поиска.
Если нужно сохранить результаты поиска из предыдущего примера в файл, нужно для этого дать команду:
$ find / -name core > /tmp/corefiles 2> /dev/null
Здесь конструкция > /tmp/corefiles перенаправляет вывод утилиты find (по каналу STDOUT) в файл /tmp/corefiles. Сообщения об ошибках отсеиваются на /dev/null, не попадая в вывод терминала командной консоли.
Для связывания между собой разных каналов для разных команд:
$ fsck --help | drep M
-M не проверять примонтированные файловые системы
Эта команда выведет строку (или строки), содержащие символ «M» из страницы быстрой справки к утилите fsck. Это очень удобно, когда нужно посмотреть только интересующую информацию. В данном случае утилита grep получает вывод (по инструкции |) от команды fsck —help. И далее по шаблону «M» отбрасывает всё лишнее.
Если нужно, чтобы следующая в конвейере команда выполнялась только после полного и успешного завершения предыдущей команды, то для этого следует использовать инструкцию &&, например:
$ lpr /tmp/t2 && rm /tmp/page1
Эта команда удалит файл /tmp/page1 только тогда, когда содержимое из него будет отправлено из очереди на печать. Для достижения обратного эффекта, т. е. когда нужно выполнение следующей команды в конвейере только после того, как предыдущая не выполнится (завершится с ошибкой с ненулевым кодом), то следует использовать конструкцию ||.
Когда строка кода, включающая слишком длинный конвейер команд тяжело воспринимается, можно разбивать её на логические компоненты по строкам с помощью символа обратной черты «\»:
$ ср --preserve --recursive /etc/* /spare/backup \ || echo "Make backup error"
Отдельные команды, которые должны выполняться друг за другом можно объединять в одну строку, разделяя их символом двоеточия «;»:
hashtable
Не все объекты Powershell могут проходить через конвейер. Как написано в документации у всех типов Powershell, кроме hashtable, есть поддержка работы через конвейеры (IEnumerable). При попытке пропустить хэш-таблицу через конвейер возникнет ошибка:
Get-Service : Не удается найти службу с именем службы «System.Collections.Hashtable».
Исправить ее можно несколькими способами. Самый простой — использовать метод ‘GetEnumerator()’. Благодаря этому методу хэш-таблица становится итерируемой и вы сможете использовать индексы и ключи в следующем виде:
Параметр «ErrorAction» нужен т.к. у нас произойдет ошибка из-за ключа ‘State’. Значения хэш таблицы передаются не как целый массив (как в случае с PSCustomObject), а по отдельности. Сначала передается ключ ‘Name’ со значением ‘WinRM’, а затем ‘State’ со значением ‘Restarted’.
Еще два способа получить только ключи или только значения:
Закрытие дескрипторов файлов
Оболочка автоматически закрывает дескрипторы файлов после завершения работы скрипта. Однако, в некоторых случаях нужно закрывать дескрипторы вручную, до того, как скрипт закончит работу. Для того, чтобы закрыть дескриптор, его нужно перенаправить в
&-. Выглядит это так:
#!/bin/bash
exec 3> myfile
echo «This is a test line of data» >&3
exec 3>&-
echo «This won’t work» >&3
1 |
#!/bin/bash exec3>myfile echo»This is a test line of data»>&3 exec3>&- echo»This won’t work»>&3 |
После исполнения скрипта мы получим сообщение об ошибке.
Попытка обращения к закрытому дескриптору файла
Всё дело в том, что мы попытались обратиться к несуществующему дескриптору.
Будьте внимательны, закрывая дескрипторы файлов в сценариях. Если вы отправляли данные в файл, потом закрыли дескриптор, потом — открыли снова, оболочка заменит существующий файл новым. То есть всё то, что было записано в этот файл ранее, будет утеряно.
Стандартный вывод (stdout) [ править ]
Стандартный вывод — это поток, в который программа записывает свои выходные данные. Программа запрашивает передачу данных с операцией записи . Не все программы генерируют выходные данные. Например, команда переименования файла (называемая по-разному mv , move или ren ) не сообщает об успехе.
Если не перенаправить , стандартный вывод наследуется от родительского процесса. В случае интерактивной оболочки это обычно текстовый терминал, запускающий программу.
Дескриптор файла для стандартного вывода составляет 1 (один); POSIX <unistd.h> определение ; соответствующая переменная C <stdio.h> : аналогично, переменная C ++ <iostream> имеет вид .