Как определить, был ли запущен скрипт Python через командную строку?

Задний план

Я хотел бы, чтобы мой скрипт Python приостанавливался до выхода с использованием чего-то похожего:

raw_input("Press enter to close.")

но только если он НЕ запускается через командную строку. Программы командной строки не должны вести себя так.

Вопрос

Есть ли способ определить, был ли запущен скрипт Python из командной строки:

$ python myscript.py

стихи, дважды щелкнув myscript.py чтобы открыть его с помощью интерпретатора по умолчанию в ОС?

Я не думаю, что есть надежный способ обнаружить это (особенно в кросс-платформенной манере). Например, в OS X, когда вы дважды щелкаете файл .py и он настраивается на «Python Launcher», он запускается в терминале, идентично, если вы выполняете его вручную.

Хотя у него могут быть и другие проблемы, вы можете скомпилировать скрипт с помощью чего-то вроде py2exe или Platypus , тогда вы можете иметь значок с двойным щелчком, который запускает определенный бит кода для дифференциации ( import mycode; mycode.main(gui = True) для пример)

Если вы используете его без терминала, как когда вы нажимаете «Выполнить» в Nautilus, вы можете просто проверить, привязан ли он к tty:

 import sys if sys.stdin.isatty(): # running interactively print "running interactively" else: with open('output','w') as f: f.write("running in the background!\n") 

Но, как указывает ThomasK, вы, похоже, ссылаетесь на запуск его в терминале, который закрывается сразу после завершения программы. Я думаю, что нет способа сделать то, что вы хотите, без обходного пути; программа работает в обычной оболочке и прикрепляется к терминалу. Решение о выходе немедленно выполняется сразу после того, как оно заканчивается с информацией, которую он не имеет в наличии (параметры передаются исполняющей оболочке или терминалу).

Вы можете изучить информацию о родительском процессе и обнаружить различия между двумя типами вызовов, но в большинстве случаев это, вероятно, не стоит. Рассматривали ли вы добавление параметра командной строки в свой скрипт (think --interactive )?

Если вы запускаете идентификатор python, тогда для запуска кодирования используется «pythonw.exe», а при запуске командной строки «python.exe» используется для запуска кодирования. Путь к папке python может изменяться, поэтому вам нужно вернуть путь к папке python. m = '\\' и m = m [0] – заставить m быть '\' из-за экранирования.

 import sys a = sys.executable m = '\\' m = m[0] while True: b = len(a) c = a[(b - 1)] if c == m: break a = a[:(b - 1)] if sys.executable == a + 'pythonw.exe': print('Running in Python IDLE') else: print('Running in Command line') 

Обычно это делается вручную /, я не думаю, что есть автоматический способ сделать это, который работает для каждого случая.

Вы должны добавить аргумент --pause к вашему скрипту, который делает подсказку для ключа в конце.

Когда скрипт вызывается из командной строки вручную, пользователь может добавить --pause если это необходимо, но по умолчанию ждать не будет.

Когда скрипт запускается из значка, аргументы в значке должны содержать --pause , так что есть ожидание. К сожалению, вам нужно будет либо документировать использование этого параметра, чтобы пользователь знал, что его нужно добавить при создании значка, либо предоставить функцию создания значков в вашем скрипте, который работает для вашей целевой ОС.

Мое решение заключалось в создании сценариев командной строки с помощью setuptools. Ниже перечислены соответствующие разделы myScript.py:

 def main(pause_on_error=False): if run(): print("we're good!") else: print("an error occurred!") if pause_on_error: raw_input("\nPress Enter to close.") sys.exit(1) def run(): pass # run the program here return False # or True if program runs successfully if __name__ == '__main__': main(pause_on_error=True) 

И соответствующие части setup.py:

 setup( entry_points={ 'console_scripts': [ 'myScript = main:main', ] }, ) 

Теперь, если я открою myScript.py с помощью интерпретатора Python (в Windows), консольное окно ждет, когда пользователь нажмет клавишу enter, если возникла ошибка. В командной строке, если я запустил «myScript», программа никогда не будет ждать ввода пользователя перед закрытием.

Я считаю, что это МОЖЕТ быть сделано. По крайней мере, вот как я получил его в Python 2.7 под Ubuntu 14.04:

 #!/usr/bin/env python import os, psutil # do stuff here if psutil.Process(os.getpid()).parent.name == 'gnome-terminal': raw_input("Press enter to close...") 

Обратите внимание: в Ubuntu 14 с рабочим столом Gnome (также известный как Nautilus) вам может понадобиться сделать следующее:

  • из окна Nautilus (браузер файлов) выберите «Редактировать» (меню) -> «Настройки» (пункт), затем «Поведение» (вкладка) -> «Исполняемые текстовые файлы» (раздел) -> «Запросить каждое время» (радио).
  • chmod, ваш скрипт будет исполняемым, или – из окна Nautilus (браузер файлов) – щелкните правой кнопкой мыши по файлу-> Свойства (элемент), затем Разрешения (вкладка) -> Выполнить: Разрешить выполнение файла как программы (флажок)
  • дважды щелкните файл. Если вы выберете «Запустить в терминале», вы увидите сообщение «Введите ввод, чтобы закрыть …».
  • теперь попробуйте выполнить подсказку bash; вы не должны видеть подсказку.

Чтобы понять, как это работает, вы можете играть с этим (на основе ответа от @EduardoIvanec):

 #!/usr/bin/env python import os import sys import psutil def parent_list(proc=None, indent=0): if not proc: proc = psutil.Process(os.getpid()) pid = proc.pid name = proc.name pad = " " * indent s = "{0}{1:5d} {2:s}".format(pad, pid, name) parent = proc.parent if parent: s += "\n" + parent_list(parent, indent+1) return s def invoked_from_bash_cmdline(): return psutil.Process(os.getpid()).parent.name == "bash" def invoked_as_run_in_terminal(): return psutil.Process(os.getpid()).parent.name == "gnome-terminal" def invoked_as_run(): return psutil.Process(os.getpid()).parent.name == "init" if sys.stdin.isatty(): print "running interactively" print parent_list() if invoked_as_run_in_terminal(): raw_input("Type enter to close...") else: with open('output','w') as f: f.write("running in the background!\n") f.write("parent list:\n") f.write(parent_list()) 

Хотя это не очень хорошее решение, оно работает (по крайней мере, в окнах).

Вы можете создать пакетный файл со следующим содержимым:

 @echo off for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1 start <location of python script> if defined DOUBLECLICKED pause 

Если вы хотите сделать это с помощью одного файла, вы можете попробовать следующее:

 @echo off setlocal EnableDelayedExpansion set LF=^ :: The 2 empty lines are necessary for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1 echo print("first line of python script") %LF% print("second and so on") > %temp%/pyscript.py start /wait console_title pyscript.py del %temp%/pyscript.py if defined DOUBLECLICKED pause 

Код пакета из: приостановка пакетного файла при двойном щелчке, но не при запуске из окна консоли? Многострочный пакет из DOS: работа с многострочными строками

Ладно, самый простой способ, который я нашел и сделал, – просто запустить программу в командной строке, даже если она была запущена в Python IDLE.

 exist = lambda x: os.path.exists(x) ## Doesn't matter if __name__ == '__main__': fname = "SomeRandomFileName" ## Random default file name if exist(fname)==False: ## exist() is a pre-defined lambda function jot(fname) ## jot() is a function that creates a blank file os.system('start YourProgram.py') ## << Insert your program name here os.system('exit'); sys.exit() ## Exits current shell (Either IDLE or CMD) os.system('color a') ## Makes it look cool! :p main() ## Runs your code os.system("del %s" % fname) ## Deletes file name for next time 

Добавьте это в конец своего сценария и один раз бежите от IDLE или командной строки, он создаст файл, запустит программу в CMD и выйдет из первого экземпляра. Надеюсь, это поможет! 🙂

Из идеи этого ответа добавление для совместимости с Win10 (Ripped из скрипта Python 2.7, изменение по мере необходимости):

 import os, psutil status = 1 if __name__ =="__main__": status = MainFunc(args) args = sys.argv running_windowed = False running_from = psutil.Process(os.getpid()).parent().name() if running_from == 'explorer.exe': args.append([DEFAULT OR DOUBLE CLICK ARGS HERE]) running_windowed = True if running_windowed: print('Completed. Exit status of {}'.format(status)) ready = raw_input('Press Enter To Close') sys.exit(status) 

Существует ряд операторов типа switch, которые вы можете добавить, чтобы быть более универсальными или обрабатывать разные значения по умолчанию.