通过Cron从目录运行程序

3 投票
4 回答
5341 浏览
提问于 2025-04-17 14:28

我在一台使用UNIX的OSX电脑上。我有一个Python程序想要每小时运行一次,所以我在编辑器里设置了一个简单的定时任务命令:

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

不过我还没实际尝试过,因为我已经遇到了一些问题。我试着从我的家目录直接运行这个命令 python Documents/workspace/programfolder/src/ProgramToRun.py,但脚本找不到它依赖的任何文件。就好像这个程序在我的家目录里运行,找不到它需要的文件。如果我进入程序所在的文件夹,然后运行 python ProgramToRun.py,那就没问题。所以我的问题是,如何让定时任务(cron)把这个程序当作是在它的目录下运行呢?我给的这个目录路径能用吗,还是需要给一个更绝对的路径,比如 /Users/MyName...等等?

4 个回答

2

在OS X上,正如文档所说:

虽然cron仍然被支持,但不推荐使用。它已经被launchd取代。

如果你对cron非常熟悉,比如你有丰富的Unix经验,或者你在OS X和Linux上都在做同样的事情,或者你有其他合理的理由,那你可以继续使用cron。但显然,这里并不是这种情况。

如果你使用的是launchd,那么这里的答案就简单多了。从手册页面来看:

WorkingDirectory <string>

这个可选的键用于指定在运行任务之前要切换到的目录。

或者,如果你想修改运行应用程序时使用的环境(例如,把它的目录放入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用户看到这个会说:“哇,这真是太啰嗦了。”我同意。不过,它并没有被淘汰。而且,它有额外的功能,与休眠的交互也有很好的文档说明,配置起来也很简单等等。而且,苹果的文档中有很多示例和解释会告诉你如何让这个工作,而cron几乎只有手册和一些说“如果你知道自己在做什么,那就用吧,但我们不会帮你”的文件。

4

在你开始做相对路径相关的操作之前,把这个放在你脚本的最上面。

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'))

8

你可以用两种方法来做到这一点:

第一种方法

先进入包含Python脚本和依赖文件的文件夹,然后从那里运行脚本,具体操作如下:

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

这里的括号表示一个“子进程”。可以把它想象成一个连续的会话,所有命令都会在这个会话中运行。&&的作用类似于;,但如果前一个命令失败,它就不会执行下一个命令。

第二种方法

ProgramToRun.py文件中,将Documents/workspace/programfolder/src/添加到PYTHONPATH,具体操作如下:

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

希望这对你有帮助。

撰写回答