ChatGPT解决这个技术问题 Extra ChatGPT

如何让 CRON 调用正确的路径

我试图让 cron 调用正确的路径。当我从 shell 运行 Python 脚本时,脚本运行良好,因为它使用 bashrc 中设置的 PATH,但是当我使用 cron 时,所有 PATH 都没有从 bashrc 中使用。是否有一个文件我可以像 bashrc 一样为 cron 输入 PATH 或从 bashrc 调用 PATH 的方法?

抱歉,我认为我的措辞不正确,我可以运行正确的脚本(这意味着 crontab 中脚本的 PATH 在这里不是问题),只是在该脚本运行时我运行了一个构建,这使用.bashrc 中设置的 PATH。当我登录后运行脚本时,会拉入 .bashrc 路径。由于 cron 不会在 shell 中运行,因此它不会拉入 .bashrc。有没有一种方法可以在无需编写 bash 脚本包装器的情况下将其引入?

还请查看此处给出的关于如何使 bashrc 设置适用于 cronjobs 的建议:stackoverflow.com/q/15557777/1025391
将您的配置文件包含在当前环境中的神奇、简单且正确的命令是 source /etc/profile,它应该吃掉 .bashrc 和许多其他可能为您丢失的东西。如果您希望某些脚本“独立”运行,则显式配置文件来源非常有用,它还可以防止奇怪的环境等等......
@exa +100 这使得 crontab 调用的 sh 脚本工作。您可以通过添加类似 * * * * * echo $PATH > ~/crontab_path.txt 的作业并在一分钟后检查文件来确认它是否更新了路径。

t
tambre

我使用了 /etc/crontab。我使用 vi 并在此文件中输入了我需要的 PATH 并以 root 身份运行它。正常的 crontab 会覆盖您设置的 PATH。 A good tutorial on how to do this

系统范围的 cron 文件如下所示:

This has the username field, as used by /etc/crontab.
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file.
# This file also has a username field, that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user   command
42 6 * * *   root    run-parts --report /etc/cron.daily
47 6 * * 7   root    run-parts --report /etc/cron.weekly
52 6 1 * *   root    run-parts --report /etc/cron.monthly
01 01 * * 1-5 root python /path/to/file.py

这在用户级别与 crontab -e 一起使用,这样也更安全。
我可以使用 bash 代替 sh 吗?
奇怪的是(对我来说)@chrissygormley 所示在 /etc/crontab 中设置的默认 PATH 以及在我的(Ubuntu)crontab 中设置的默认路径与 /etc/environment 中的路径不同,特别是它放置 /sbin 和/bin 在 /usr/sbin 和 /usr/bin 之前。我现在在我的 /etc/crontab 中更改了它,使其与用户环境相同。
不适合我..我正在将 cron 内容输出到文件中。 Cron 运行,文件创建,但它没有在其中放入任何内容。
在 Ubuntu 14.04 中以 root 身份运行时,似乎并非 /etc/crontab 中设置的所有路径都可用于 cron。 (sudo crontab -e)
j
joemaller

最有可能的是,cron 运行在一个非常稀疏的环境中。检查 cron 正在使用的环境变量,方法是附加一个将 env 转储到如下文件的虚拟作业:

* * * * * env > env_dump.txt

将其与正常 shell 会话中 env 的输出进行比较。

您可以通过在 crontab 顶部定义它们来将自己的环境变量添加到本地 crontab。

这是将 $PATH 添加到当前 crontab 的快速修复:

# echo PATH=$PATH > tmp.cron
# echo >> tmp.cron
# crontab -l >> tmp.cron
# crontab tmp.cron

生成的 crontab 看起来类似于 chrissygormley 的答案,在 crontab 规则之前定义了 PATH 。


D
Douglas Leeder

您应该将完整路径放入您的 crontab。这是最安全的选择。
如果您不想这样做,可以在程序周围放置一个包装脚本,并在其中设置 PATH。

例如

01 01 * * * command

变成:

01 01 * * * /full/path/to/command

此外,从 cron 调用的任何程序都应该非常小心它运行的程序,并可能为 PATH 变量设置自己的选择。

编辑:

如果您不知道要从 shell 执行 which <command> 的命令在哪里,它会告诉您路径。

编辑2:

因此,一旦您的程序运行,它应该做的第一件事就是将 PATH 和任何其他必需的变量(例如 LD_LIBRARY_PATH)设置为脚本运行所需的值。
基本上而不是考虑如何修改 cron 环境以使其更适合您的程序/脚本 - 通过在启动时设置一个适当的环境,使您的脚本能够处理给定的环境。


如果它在您的路径中,请使用“哪个命令”,它将为您提供完整路径
@Douglas Leeder - 当您说将完整路径放入 cron 时,您的意思是将其放入 crontab 或其他文件中吗?如果 cron 命令是:'01 01 * * * command',你会怎么做。谢谢
@chrissygormley - 是的crontab
抱歉,一定是有些混乱。我已经改写了上面的问题。
您应该更喜欢 type 和/或 command 而不是 whichwhereis 等非标准实用程序。有时它们存在并起作用,有时它们不存在。
T
Treviño

将 PATH 定义添加到具有正确值的用户 crontab 将有所帮助...我已经在顶部填充了这一行(在评论之后,在 cron 作业之前):

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

这足以让我的所有脚本正常工作......如果需要,请在其中包含任何自定义路径。


对于用户 crontab,这应该是正确的答案。并非系统上的每个人都可以编辑 /etc/crontab。这是用户级别上最简单的答案。干得好@Treviño。如果您同意,请投票。
也许与您的交互式 PATH 和系统的默认 PATH 进行比较,并进行相应调整。例如,/usr/local/sbin 有点不寻常,但在 OP 的系统上可能是正确的。带有 sbin 的那些往往是管理命令,对于普通用户,它们通常不在默认的 PATH 上,因此您可能不需要这些命令。
一些第三方软件包将其二进制文件安装在 /opt/acme 之类的位置,因此您需要添加 /opt/acme/bin 或者可能是 /opt/acme/ajax/bin 以将它们添加到您的 PATH 中。或者,当然,为了快速而肮脏的一次性,只需硬编码您要运行的二进制文件的位置,例如 /opt/acme/ajax/bin/anvil 而不是 anvil
g
gilad905

在我的 crontab 中的命令行之前设置 PATH 对我有用:

* * * * * PATH=$PATH:/usr/local/bin:/path/to/some/thing

更喜欢这种方式。或指定脚本的完整路径。
我认为路径不会继续增长,每次运行都会是一个新环境,带有一个新的 PATH 副本......
可以确认@jjcf89 是正确的,PATH 每次运行都是新鲜的。
A
Artistan

让你的变量为你工作,这将允许访问

在 /etc/profile.d/*.sh 中定义您的 PATH

System-wide environment variables

每当输入 bash 登录 shell 时(例如,从控制台或通过 ssh 登录时)以及在桌面会话加载时由 DisplayManager 执行,/etc/profile.d 目录中具有 .sh 扩展名的文件都会被执行。

例如,您可以创建文件 /etc/profile.d/myenvvars.sh 并设置如下变量:

export JAVA_HOME=/usr/lib/jvm/jdk1.7.0
export PATH=$PATH:$JAVA_HOME/bin

使用登录选项执行 crontab!

CRONTAB run script or command with Environment Variables

0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c 'php -f ./download.php'
0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c download.sh

/etc/profile.d 是 Debian 的一项发明。对于具有此目录的系统,这是隐约合理的,尽管并非以任何方式具体到 cron 作业;因此,您可能希望避免污染无关工作的环境,并寻求不同的解决方案。
b
brakertech

问题

您的脚本在您从控制台运行时有效,但在 cron 中失败。

原因

您的 crontab 没有正确的路径变量(可能还有 shell)

解决方案

添加您当前的 shell 和路径 crontab

为您执行此操作的脚本

#!/bin/bash
#
# Date: August 22, 2013
# Author: Steve Stonebraker
# File: add_current_shell_and_path_to_crontab.sh
# Description: Add current user's shell and path to crontab
# Source: http://brakertech.com/add-current-path-to-crontab
# Github: hhttps://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

# function that is called when the script exits (cleans up our tmp.cron file)
function finish { [ -e "tmp.cron" ] && rm tmp.cron; }

#whenver the script exits call the function "finish"
trap finish EXIT

########################################
# pretty printing functions
function print_status { echo -e "\x1B[01;34m[*]\x1B[0m $1"; }
function print_good { echo -e "\x1B[01;32m[*]\x1B[0m $1"; }
function print_error { echo -e "\x1B[01;31m[*]\x1B[0m $1"; }
function print_notification { echo -e "\x1B[01;33m[*]\x1B[0m $1"; }
function printline { 
  hr=-------------------------------------------------------------------------------------------------------------------------------
  printf '%s\n' "${hr:0:${COLUMNS:-$(tput cols)}}"
}
####################################
# print message and exit program
function die { print_error "$1"; exit 1; }

####################################
# user must have at least one job in their crontab
function require_gt1_user_crontab_job {
        crontab -l &> /dev/null
        [ $? -ne 0 ] && die "Script requires you have at least one user crontab job!"
}


####################################
# Add current shell and path to user's crontab
function add_shell_path_to_crontab {
    #print info about what's being added
    print_notification "Current SHELL: ${SHELL}"
    print_notification "Current PATH: ${PATH}"

    #Add current shell and path to crontab
    print_status "Adding current SHELL and PATH to crontab \nold crontab:"

    printline; crontab -l; printline

    #keep old comments but start new crontab file
    crontab -l | grep "^#" > tmp.cron

    #Add our current shell and path to the new crontab file
    echo -e "SHELL=${SHELL}\nPATH=${PATH}\n" >> tmp.cron 

    #Add old crontab entries but ignore comments or any shell or path statements
    crontab -l | grep -v "^#" | grep -v "SHELL" | grep -v "PATH" >> tmp.cron

    #load up the new crontab we just created
    crontab tmp.cron

    #Display new crontab
    print_good "New crontab:"
    printline; crontab -l; printline
}

require_gt1_user_crontab_job
add_shell_path_to_crontab

资源

https://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

样本输出

https://i.stack.imgur.com/VHOro.png


佚名

我发现的最简单的解决方法如下所示:

* * * * * root su -l -c command

此示例以 root 用户身份调用 su 并使用用户的完整环境(包括 $PATH)启动 shell,就像他们已登录一样。它在不同发行版上的工作方式相同,比采购 .bashrc(没有t 为我工作)并避免硬编码特定路径,如果您提供示例或设置工具并且不知道用户系统上的发行版或文件布局,这可能是一个问题。

如果您想要与 root 不同的用户,您还可以在 su 之后指定用户名,但您可能应该在 su 命令之前保留 root 参数,因为这可以确保 su 有足够的权限切换到您指定的任何用户.


很惊讶这没有更多的赞成票。我测试并确认它有效。这绝对是为用户拉入所有路径的最简单方法。用户应该注意哪些缺点?
m
mob

cron 作业的默认环境非常稀疏,可能与您在其中开发 python 脚本的环境有很大不同。对于可能在 cron 中运行的脚本,您所依赖的任何环境都应该明确设置。在 cron 文件本身中,包含 python 可执行文件和 python 脚本的完整路径。


V
Van Amburg

在我的 AIX cron 上,它从 /etc/environment 获取它的环境变量,而忽略了 .profile 中设置的内容。

编辑:我还检查了几个不同年龄的 Linux 机器,这些机器似乎也有这个文件,所以这可能不是特定于 AIX 的。

我使用 joemaller 的 cron 建议检查了这一点,并在编辑 /etc/environment 中的 PATH 变量之前和之后检查了输出。


W
Wade Chandler

如果您不想在不同的地方进行相同的编辑,那么大致这样做:

* * * * * . /home/username/.bashrc && yourcommand all of your args

这 。空间,然后是 .bashrc 的路径和 && 命令是让你的环境更改到正在运行的 bash shell 中的魔法。同样,如果你真的希望 shell 是 bash,那么在你的 crontab 中有一行是个好主意:

SHELL=/bin/bash

希望它可以帮助某人!


这有点可疑,因为 .bashrc 主要是交互式 shell 调用的配置,因此通常包含与 cron 作业无关且可能不适合的内容。一个更有原则的解决方案是将您想要的设置分解到一个单独的文件中,然后从其他各个位置 .(源)该文件,即您的 cron 作业和您的 .profile 等。
R
Ram Dwivedi

@Trevino:您的回答帮助我解决了我的问题。但是,对于初学者来说,尝试给出一步一步的方法。

通过 $ echo $JAVA_HOME $ crontab -e * * * * * echo $PATH 获取您当前的 java 安装 - 这可以让您了解 crontab 目前使用的 PATH 值是什么。运行 crontab 并获取 crontab 使用的 $PATH 值。现在再次编辑 crontab 以设置您想要的 java bin 路径: a) crontab -e; b) PATH=<$JAVA_HOME 的值>/bin:/usr/bin:/bin(它的示例路径); c) 现在您的计划作业/脚本如 */10 * * * * sh runMyJob.sh &; d) 从 crontab 中删除 echo $PATH,因为它现在不需要。


Y
Yogesh Yadav

在您的 cron 中设置所需的 PATH

crontab -e

编辑:按 i

PATH=/usr/local/bin:/usr/local/:or_whatever

10 * * * * your_command

保存并退出 :wq


“按 i”的说明和如何退出的指导假定读者是 vi 受害者。更好的解决方案可能是将 VISUAL 设置为您在 shell 配置中熟悉和熟悉的编辑器的路径,例如 export VISUAL=/usr/bin/emacsclient
C
Community

我知道这已经得到了回答,但我认为他对某些人会有用。我最近解决了一个类似的问题 (found here),以下是我为回答这个问题所采取的步骤的重点:

确保您在 PYTHONPATH 中拥有所需的变量(可在此处和此处找到,并在此处获取更多信息)内的 .profile 或 .bash_profile 用于您想要测试脚本以确保其正常工作的任何 shell。编辑您的 crontab 以包含在 cron 作业中运行脚本所需的目录(在此处和此处找到) a) 确保在 PATH 变量 (.) 中包含根目录,如此处所述(基本上,如果您正在运行一个可执行文件您的命令需要能够找到根目录或存储可执行文件的目录)以及可能在您的 crontab 文件中的这些(/sbin:/bin:/usr/sbin:/usr/bin),创建一个将更改的 cronjob目录到您之前成功运行脚本的目录(即 Users/user/Documents/foo) a) 这将如下所示: * * * * cd /Users/user/Documents/foo; bar -l doSomething -v


P
Peter VARGA

如果您使用 webmin,那么这些是如何设置 PATH 值的步骤:

System
  -> Scheduled Cron Jobs
       -> Create a new environment variable
            -> For user: <Select the user name>
            -> Variable name: PATH
            -> Value: /usr/bin:/bin:<your personal path>
            -> Add environment variable: Before all Cron jobs for user