Как определить, был ли скрипт Python запущен из командной строки? - PullRequest
22 голосов
/ 23 марта 2012

Фон

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

raw_input("Press enter to close.")

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

Вопрос

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

$ python myscript.py

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

Ответы [ 10 ]

14 голосов
/ 23 марта 2012

Если вы используете его без терминала, как, например, когда вы нажимаете «Выполнить» в 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вы, кажется, имеете в виду запуск его в терминале, который закрывается сразу после завершения программы.Я думаю, что нет способа сделать то, что вы хотите без обходного пути;программа работает в обычной оболочке и подключена к терминалу.Решение о немедленном выходе принимается сразу после того, как оно заканчивается информацией, которой у него нет легкого доступа (параметры, переданные в исполняющую оболочку или терминал).

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

4 голосов
/ 23 марта 2012

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

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

2 голосов
/ 12 июня 2014

Если вы запускаете python IDLE, то для запуска кодирования используется pythonw.exe, а при запуске командной строки python.exe - для кодирования.Путь к папке с питоном может варьироваться, поэтому вам нужно вернуть путь к папке с питоном.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')
1 голос
/ 01 февраля 2016

Я верю, что это МОЖЕТ быть сделано. По крайней мере, вот как у меня это работает в 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 (файловый браузер) - щелкните правой кнопкой мыши файл-> Свойства (элемент), затем Разрешения (вкладка) -> Выполнить: разрешить выполнение файла как программы ( флажок)
  • дважды щелкните ваш файл. Если вы выберете «Запустить в терминале», вы должны увидеть подсказку «Введите enter to close ...».
  • теперь попробуйте из командной строки 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())
1 голос
/ 04 мая 2012

Моим решением было создание сценариев командной строки с использованием 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), окно консоли ожидает, когда пользователь нажмет ввод, если произойдет ошибка.В командной строке, если я запускаю «myScript», программа никогда не будет ждать ввода пользователя перед закрытием.

1 голос
/ 23 марта 2012

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

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

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

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

0 голосов
/ 27 декабря 2017

У меня тоже был этот вопрос, и для меня лучшее решение - установить переменную окружения в моей IDE (PyCharm) и проверить, существует ли эта переменная, чтобы узнать, выполняется ли сценарий либо через командную строку, либо черезIDE.

Чтобы установить переменную среды в проверке PyCharm: Как установить переменные среды в PyCharm?

Пример кода (переменная среды: RUNNING_PYCHARM = True):

import os

# The script is being executed via the command line
if not("RUNNING_PYCHARM" in os.environ):
    raw_input("Press enter to close.")

Я надеюсь, что это работает для вас.

0 голосов
/ 06 марта 2017

Исходя из идеи этого ответа, добавление для совместимости с Win10 (Извлечено из скрипта 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, которые можно добавить, чтобы сделать их более универсальными или использовать разные значения по умолчанию.

0 голосов
/ 13 января 2015

Хорошо, самый простой способ, который я нашел и сделал, - это просто запустить программу из командной строки, даже если она запускалась в 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 и выйдет из первого экземпляра. Надеюсь, это поможет! :)

0 голосов
/ 31 декабря 2013

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

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

@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

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

...