如何确定Python脚本是否通过命令行运行?

时间:2012-03-23 12:32:08

标签: python command-line

背景

我希望我的Python脚本在退出之前暂停使用类似于:

的内容

raw_input("Press enter to close.")

但仅限于不通过命令行运行。命令行程序不应该这样。

问题

有没有办法确定我的Python脚本是否是从命令行调用的:

$ python myscript.py

双击myscript.py并使用操作系统中的默认解释器打开它?

11 个答案:

答案 0 :(得分:14)

如果您在没有终端的情况下运行它,就像在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所指出的那样,你似乎指的是在程序结束后关闭的终端中运行它。我认为没有解决办法就没办法做你想做的事;程序在常规shell中运行并附加到终端。立即退出的决定是在它完成后没有随时可用的信息(传递给执行的shell或终端的参数)之后完成的。

你可以去examining the parent process information并检测两种调用之间的差异,但在大多数情况下它可能不值得。您是否考虑过在命令行中添加命令行参数(想想--interactive)?

答案 1 :(得分:4)

我认为没有任何可靠的方法来检测这种情况(特别是以跨平台的方式)。例如,在OS X上,双击.py文件并使用“Python Launcher”进行调整时,它会在终端中运行,与手动执行时相同。

虽然它可能有其他问题,但您可以使用py2exePlatypus之类的方法打包脚本,然后您可以使用双击图标运行特定的代码来区分({ {1}}例如)

答案 2 :(得分:2)

如果你运行python IDLE,那么“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')

答案 3 :(得分:2)

我想要的在这里得到了回答:Determine if the program is called from a script in Python

您可以在“ python”和“ bash”之间确定。我认为已经回答了这个问题,但是您也可以将其简短。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import psutil
import os

ppid = os.getppid() # Get parent process id
print(psutil.Process(ppid).name())

答案 4 :(得分:1)

这通常是手动完成的,我不认为有一种自动方式可以适用于每种情况。

您应该在脚本中添加一个--pause参数,以便在最后提示输入密钥。

当手动从命令行调用脚本时,如果需要,用户可以添加--pause,但默认情况下不会有任何等待。

从图标启动脚本时,图标中的参数应包含--pause,以便等待。遗憾的是,您需要记录此选项的使用,以便用户知道在创建图标时需要添加该选项,或者在脚本中提供适用于目标操作系统的图标创建功能。

答案 5 :(得分:1)

我的解决方案是使用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',
        ]
    },
)

现在,如果我使用Python解释器(在Windows上)打开myScript.py,则控制台窗口会等待用户在发生错误时按Enter键。在命令行中,如果我运行'myScript',程序将永远不会在关闭之前等待用户输入。

答案 6 :(得分:1)

我相信这可以做到。至少,这是我在Ubuntu 14.04下使用Python 2.7的方法:

#!/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窗口(文件浏览器),选择编辑(菜单) - &gt;首选项(项目),然后选择行为(标签) - &gt;可执行文本文件(部分) - &gt;每次询问(广播)。< / LI>
  • chmod你的脚本是可执行的,或者 - 从Nautilus窗口(文件浏览器) - 右键单击​​文件 - > gt;属性(项目)然后权限(选项卡) - &gt;执行:允许执行文件为程序(复选框)
  • 双击您的文件。如果选择“在终端中运行”,则应该会看到“输入以关闭...”提示。
  • 现在尝试从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())

答案 7 :(得分:0)

虽然这不是一个非常好的解决方案,但它确实有效(至少在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

批量代码来自:Pausing a batch file when double-clicked but not when run from a console window? 批量多行来自:DOS: Working with multi-line strings

答案 8 :(得分:0)

好的,我发现和制作的最简单方法是在命令行中运行程序,即使它是在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中重新运行该程序,并退出第一个实例。 希望有所帮助! :)

答案 9 :(得分:0)

this回答背后的想法,添加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)

您可以添加许多类似于开关的语句,以使其更具通用性或处理不同的默认值。

答案 10 :(得分:0)

我也有这个问题,对我来说,最好的解决方案是在我的IDE(PyCharm)中设置一个环境变量,并检查该变量是否存在,以通过命令行或通过IDE。

要在PyCharm中设置环境变量,请检查: How to set environment variables in 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.")

我希望它适合你。