首页 > 解决方案 > 知道 python 脚本在由 crontab 启动时可以从标准输入中读取一些内容

问题描述

我有一个由 crontab 运行的 python 脚本,可以手动执行。

该脚本作为输入:

代码应该是这样的:

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 执行时不能按预期工作:脚本始终认为有来自标准输入的数据。

第一次测试:

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 模式?

标签: pythonlinuxpython-3.xcronstdin

解决方案


正如 Nullman 已经在评论中所写,最好检查您的命令行选项以决定是否要尝试stdin

简短摘要:您无法安全地猜测是否应该stdin通过检查来读取数据stdin。您应该只依靠检查命令行来找出预期的内容。

例如,仅当没有将输入文件指定为命令行参数或指定了特殊文件名时cat才会使用。stdin-


您示例中的所有测试仅在某些条件下有效,而在其他情况下无效。

检查是否stdin是 TTY 没有帮助。它只会告诉您它是否连接到终端。如果用户键入某些内容或者它是连接到其他内容的伪终端,您的脚本可以从终端获取输入。stdin如果您的脚本没有连接到终端,而是连接到其他东西(管道、文件、套接字......),您的脚本也可以从中获取输入

检查是否stdin是 FIFO 也是错误的,因为您可以从管道/fifo 或其他东西(文件、套接字、终端......)读取数据。

usingselect不会告诉你是否有任何数据,但只会告诉你 aread不会阻塞。它也不会阻塞 EOF。要区分这些情况,您必须检查 a readfrom的结果stdin。如果没有延迟/超时,它也可能会告诉您read如果数据尚不可用 a 将阻塞。

还有更多使用脚本的方法:

而不是cat myInput | ./myscript.py你也可以使用./myscript.py < myInput. 在第一种情况下stdin是一个管道,在第二种情况下是一个文件。

或者想象一下./myscript.py < /dev/null。这将在第一个返回 EOF 条件read
或者当您尝试从中读取时./myscript.py <&-会关闭stdin导致错误。

如果stdin连接到终端,read如果用户不输入任何内容,则可能会阻塞。如果您调用./myscript.py. 您可以使用select来确定数据是否现在可用,但您无法确定用户稍后是否会输入数据。所以你的脚本不知道用户的意图。


推荐阅读