Зная, что скрипту на python есть что почитать из stdin при запуске crontab - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть скрипт на python, который запускается crontab и может быть выполнен вручную.

Этот скрипт принимает за вход:

  • либо значение из -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: скрипт всегда учитывает данные IS из stdin.

Первый тест:

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?

1 Ответ

2 голосов
/ 30 апреля 2019

Как уже писал Нулман в комментарии, лучше проверить параметры командной строки, чтобы решить, хотите ли вы попробовать 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.Это вернет условие EOF для первого read.
или ./myscript.py <&-, которое закроет stdin, что приведет к ошибке при попытке чтения из него.

Если stdin подключен ктерминал, который read может заблокировать, если пользователь ничего не вводит.Это произойдет, если вы позвоните ./myscript.py.Вы можете использовать select, чтобы узнать, доступны ли данные сейчас , но вы не можете узнать, введет ли пользователь данные позже.Таким образом, ваш сценарий не знает намерения пользователя.

...