Last Updated: 2023-04-06 07:08:55 Thursday
-- TOC --
程序代码自身并不知道stdin的输入来自哪里,tty或pipeline,只要读取stdin就行了。要让python代码接收来自pipeline的输入,就是读取stdin,但关键是不能让程序block,当stdin没有输入的时候,sys.stdin.read
等一系列read函数接口,默认会陷入阻塞。
默认stdin和stdout是line buffered模式,并且是block模式,stderr是unbuffered,程序运行关键的异常或调试信息,建议都向stderr输出。
Python内置的input接口,可以按行读取stdin,每次调用input,它都会尝试以阻塞的方式从stdin读一行。
代码:
print(input())
print(input())
测试:
$ echo -e 'abcde\n12345' | python3 test_input.py
abcde
12345
$ echo 'abcde' | python3 test_input.py
abcde
Traceback (most recent call last):
File "test_input.py", line 2, in <module>
print(input())
EOFError: EOF when reading a line
$ echo -e 'abcde\n12345\nskipped' | python3 test_input.py
abcde
12345
echo命令的-e参数是必要的。
第1次测试正常,输入两行,用input读取两行。第2次测试,第2次调用input时读到了EOF,raise了。最后一个测试有3行数据输入,但是代码只调用两次input,最后一行数据就丢掉了。
Python代码直接读取stdin,关键是不能block,我们可以在程序的一开始,设置stdin为nonblock模式。
代码:
import os
import sys
from fcntl import *
print('stdin is blocking:',os.get_blocking(sys.stdin.fileno()))
fcntl(sys.stdin, F_SETFL, fcntl(sys.stdin,F_GETFL)|os.O_NONBLOCK)
print('stdin is blocking:',os.get_blocking(sys.stdin.fileno()))
print('readlines from stdin:', sys.stdin.readlines())
测试:
$ echo -e '123\nabc' | python3 pipe.py
stdin is blocking: True
stdin is blocking: False
readlines from stdin: ['123\n', 'abc\n']
$ python3 pipe.py
stdin is blocking: True
stdin is blocking: False
readlines from stdin: []
第2次测试,当stdin为空时,在nonblock模式下,也不会阻塞了。
注意:
当Python程序通过管道接收数据时,stdin一定不是一个tty!只要判断stdin是否为tty,就可以不用设置stdin为nonblock模式。python有两种方法来判断stdin是否为tty:
>>> import sys
>>> sys.stdin.isatty()
True
>>> import os
>>> os.isatty(sys.stdin.fileno())
True
当stdin如果不是tty时,此时就直接读取stdin,获取来自pipeline的数据,而不需要设置stdin为nonblock,因为此时一定存在来自pipeline的重定向,否则stdin就是tty了。
代码:
import sys
if not sys.stdin.isatty():
print(sys.stdin.read())
else:
print('----')
测试:
$ python3 stdin_tty.py
----
$ echo -n '12345678' | python3 stdin_tty.py
12345678
$ python3 stdin_tty.py < kk.txt
abcdefg
使用select
判断stdin是否有数据。
代码:
import sys
from select import select
if select([sys.stdin],[],[],0)[0]:
print(sys.stdin.read())
else:
print('====')
测试:
$ python3 stdin_select.py
====
$ echo -n '12345678' | python3 stdin_select.py
12345678
$ python3 stdin_select.py < kk.txt
abcdefg
本文链接:https://cs.pynote.net/sf/python/202201011/
-- EOF --
-- MORE --