【问题标题】:Running a program from its Directory Using Cron使用 Cron 从其目录运行程序
【发布时间】:2013-02-01 18:55:42
【问题描述】:

我在使用 UNIX 的 OSX 机器上。我有一个 Python 程序,我想每隔一小时左右运行一次,所以我在编辑器中设置了一个基本的 cron 命令:

0 * * * * python Documents/workspace/programfolder/src/ProgramToRun.py

我还没有真正尝试过,因为我已经遇到了问题。我试图从我的主目录运行python Documents/workspace/programfolder/src/ProgramToRun.py 命令,但脚本无法在其目录中找到它所依赖的任何文件。就好像该程序以某种方式在我的主目录中运行并且找不到它的任何依赖项。如果我 cd 进入程序所在的文件夹并执行 python ProgramToRun.py,它工作正常。所以我的问题是如何让 cron 像从它的目录运行它一样对待这个程序?我给的目录会起作用吗,还是我需要给一些更绝对的东西,比如/Users/MyName...等?

【问题讨论】:

  • 只在命令中包含cd'ing?或者,使脚本可以在任何地方安全运行。
  • 我经常在 crontab 中使用纯 shell 脚本,然后引导真正的脚本。它使您可以灵活地查看正在发生的事情,还允许您更改代码的实现。它可能以 python 脚本开始,然后变为 exe 或其他东西。在我的 shell 脚本中,我经常使用 scriptdir=$(cd $(dirname $0); pwd) 或者在你的情况下是 cd $(dirname $0)
  • 你为什么在 OS X 上使用cron 而不是launchd?几乎所有提到cron 的文档都以"Note: Although it is still supported, cron is not a recommended solution. It has been deprecated in favor of launchd." 之类的开头。如果您已经知道cron,那是使用它的好理由,否则,为什么?

标签: python macos unix


【解决方案1】:

在你开始做相关的事情之前把它放在你脚本的顶部。

import os
scriptdir =  os.path.dirname(os.path.abspath(__file__))
os.chdir(scriptdir)

这也可能是您的脚本实际上并没有首先尝试解析相对于脚本的路径等的症状。脚本不应依赖于从与脚本相同的目录运行脚本的用户。

我通常使用scriptdir 来查找与脚本相关的内容,例如

open(os.path.join(scriptdir, 'data', 'someconfig.cfg')) 而不是open(os.path.join('data', 'someconfig.cfg'))

【讨论】:

    【解决方案2】:

    您可以通过以下两种方式之一来做到这一点:

    第一种方式

    cd 进入包含 python 脚本和依赖项的目录并从那里运行它,如下所示:

    (cd /Users/username/Documents/workspace/programfolder/src/ && python ProgramToRun.py)
    

    在这里,括号调用“子shell”。把它想象成一个所有命令都在其中运行的连续会话。 && 的作用相当于;,但如果上一个命令失败则不执行下一个命令

    第二种方式

    Documents/workspace/programfolder/src/ 添加到ProgramToRun.py 内的PYTHONPATH,如下所示:

    import sys
    sys.path.append("/Users/username/Documents/workspace/programfolder/src/")
    

    希望对你有帮助

    【讨论】:

    • 对于您的第二种方式,您仍然指定一个相对路径,因此仍然依赖于运行脚本的当前目录。我建议sys.path.append(os.path.expanduser("~/Documents/workspace/programfolder/src"))
    • 如果我选择第一个选项,是否应该应用相同的逻辑?即,由于我的 cd'ing 路径是相对的,如果我已经在 UNIX 中的某个不同目录中,程序是否能够理解这一点?或者 cron 不会在您打开的任何终端实例上运行,而是从您的主目录开始创建一个新的终端实例?
    • cron 通常从主目录运行,所以你应该没问题。但感谢@Celada 的好收获。更新了!
    【解决方案3】:

    在 OS X 上,正如 the documentation 所说:

    虽然仍受支持,但cron 不是推荐的解决方案。它已被 launchd 弃用。

    如果您已经从长期的 Unix 经验中了解了 cron,或者您正在 OS X 和 Linux 上实现相同的东西,或者您有其他好的借口,请继续使用 @987654326 @。但显然,这里不是这样。

    如果您使用的是launchd,那么这里的答案将是微不足道的。来自man page

    WorkingDirectory <string>

    此可选键用于在运行作业之前指定 chdir(2) 的目录。

    或者,如果您想修改用于运行应用程序的环境(例如,将其目录放入 PYTHONPATH),同样简单。

    这是一个示例launchd.plist 文件,用于每小时运行您的程序:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
      "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.example.ProgramToRun</string>
        <key>ProgramArguments</key>
        <array>
            <string>python</string>
            <string>Documents/workspace/programfolder/src/ProgramToRun.py</string>
        </array>
        <key>StartInterval</key>
        <integer>3600</integer>
        <key>WorkingDirectory</key>
        <string>Documents/workspace/programfolder/src/</string>
    </dict>
    </plist>
    

    很多老 Unix 手看到这个会说:“哇,这太冗长了。”并且我同意。另一方面,它并没有被弃用。此外,它还有额外的功能,它与睡眠的交互有据可查且易于配置等。Apple 文档中到处都有示例和解释,将告诉您如何进行这项工作,而 cron 基本上除了手册页和一些文档说“如果您知道自己在做什么,请继续使用它,但我们不会帮助您”。

    【讨论】:

      【解决方案4】:

      是的,您的 Python 路径中没有该目录,因此 Python 无法找到脚本尝试导入的模块。将文件夹添加到您的路径。你可以做类似的事情

      import sys
      sys.path.append(".")
      

      在您的脚本文件中,或者更好的是,使用 lib/site-packages 中的 .pth 文件来包含脚本所在的目录。

      【讨论】:

      • 如果我使用 sys.path.append(),这只是暂时改变我的 PATH,还是永久的?另外,一旦路径已经被附加,它会做什么?它会检查它是否已经存在,还是我会得到一个每次运行程序都会增长的 PATH 文件?
      • 只是暂时的。如果你想永久添加一个目录到路径,然后将该目录附加到一个 .pth 文件中,通常位于 lib/site-packages 中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-08
      • 2020-09-05
      • 2017-02-16
      • 2011-02-23
      相关资源
      最近更新 更多