我有一个由crontab运行的python脚本,可以手动执行。
此脚本作为输入:
-i
论证的价值,stdin
通过pipe
的任何东西。代码应该是这样的:
if ???: #test to check if there is some data in stdin
print("I have data from stdin!")
else:
print("I have no data from stdin!")
脚本执行如下:
$ ./myscript.py -i myInput
> I have no data from stdin!
$ cat myInput | ./myscript.py
> I have data from stdin!
我已经尝试了几种在通过控制台执行时工作正常的方法,但是在crontab执行时没有按预期工作:脚本始终认为来自stdin的IS数据。
第一次测试:
if not sys.stdin.isatty():
print("I have data from stdin!")
else:
print("I have no data from stdin!")
我认为这个不起作用,因为因为crontab模式中没有tty所以第一个语句总是正确的。
第二次测试:
import stat
mode = os.fstat(sys.stdin.fileno()).st_mode
if stat.S_ISFIFO(mode):
print("I have data from stdin!")
else:
print("I have no data from stdin!")
第三次测试:
import select
r, w, x = select.select([sys.stdin], [], [], 0)
if r:
print("I have data from stdin!")
else:
print("I have no data from stdin!")
是否有正确的方法使其适用于控制台和crontab模式?
正如Nullman已在评论中写道,最好检查一下命令行选项,以决定是否要尝试使用stdin
。
简短摘要:您无法安全地猜测是否应该通过检查stdin
来读取stdin
的数据。您应该只依靠检查命令行来找出预期的内容。
例如,仅当没有将输入文件指定为命令行参数或者指定了特殊文件名cat
时,stdin
才会使用-
。
您的示例中的所有测试仅在某些条件下有效,在其他情况下不起作用。
检查stdin
是否是TTY没有帮助。它只会告诉您它是否连接到终端。如果用户键入内容或者是连接到其他内容的伪终端,您的脚本可以从终端获取输入。你的脚本也可以从stdin
获得输入,如果它没有连接到终端而是连接到其他东西(管道,文件,套接字......)
检查stdin
是否是FIFO也是错误的,因为你可以从pipe / fifo或其他东西(文件,套接字,终端......)读取数据。
使用select
不会告诉您是否有任何数据,但仅限于read
不会阻止。它也不会阻止EOF。要区分这些情况,您必须检查来自read
的stdin
的结果。如果没有延迟/超时,它也可能会告诉您,如果数据尚未可用,read
将会阻止。
有更多方法可以使用该脚本:
而不是cat myInput | ./myscript.py
你也可以使用./myscript.py < myInput
。在第一种情况下,stdin
将是一个管道,在第二种情况下是一个文件。
或者想象./myscript.py < /dev/null
。这将返回第一个read
的EOF条件。
或./myscript.py <&-
将关闭stdin
导致错误,当你尝试从它读取。
如果stdin
连接到终端,如果用户没有输入任何内容,read
可能会阻止。如果你打电话给./myscript.py
,就会发生这种情况。您可以使用select
查看数据是否现在可用,但您无法确定用户是否稍后会输入数据。所以你的脚本不知道用户的意图。