bash 如何模拟cron执行脚本的环境?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2135478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:53:12  来源:igfitidea点击:

How to simulate the environment cron executes a script with?

bashscriptingcron

提问by Jorge Vargas

I normally have several problems with how cron executes scripts as they normally don't have my environment setup. Is there a way to invoke bash(?) in the same way cron does so I could test scripts before installing them?

我通常对 cron 如何执行脚本有几个问题,因为它们通常没有我的环境设置。有没有办法以与 cron 相同的方式调用 bash(?) 以便我可以在安装脚本之前测试它们?

回答by mmccoo

Add this to your crontab (temporarily):

将此添加到您的 crontab(临时):

* * * * * env > ~/cronenv

After it runs, do this:

运行后,执行以下操作:

env - `cat ~/cronenv` /bin/sh

This assumes that your cron runs /bin/sh, which is the default regardless of the user's default shell.

这假设您的 cron 运行 /bin/sh,无论用户的默认 shell 是什么,它都是默认值。

回答by gregseth

Cron provides only this environment by default :

Cron 默认只提供这个环境:

  • HOMEuser's home directory
  • LOGNAMEuser's login
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh
  • HOME用户的主目录
  • LOGNAME用户登录
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

If you need more you can source a script where you define your environment before the scheduling table in the crontab.

如果您需要更多,您可以在 crontab 中的调度表之前定义您的环境的脚本。

回答by Cookie

Couple of approaches:

几种方法:

  1. Export cron env and source it:

    Add

    * * * * * env > ~/cronenv
    

    to your crontab, let it run once, turn it back off, then run

    env - `cat ~/cronenv` /bin/sh
    

    And you are now inside a shsession which has cron's environment

  2. Bring your environment to cron

    You could skip above exercise and just do a . ~/.profilein front of your cron job, e.g.

    * * * * * . ~/.profile; your_command
    
  3. Use screen

    Above two solutions still fail in that they provide an environment connected to a running X session, with access to dbusetc. For example, on Ubuntu, nmcli(Network Manager) will work in above two approaches, but still fail in cron.

    * * * * * /usr/bin/screen -dm
    

    Add above line to cron, let it run once, turn it back off. Connect to your screen session (screen -r). If you are checking the screen session has been created (with ps) be aware that they are sometimes in capitals (e.g. ps | grep SCREEN)

    Now even nmcliand similar will fail.

  1. 导出 cron env 并获取它:

    添加

    * * * * * env > ~/cronenv
    

    到您的 crontab,让它运行一次,将其关闭,然后运行

    env - `cat ~/cronenv` /bin/sh
    

    你现在在一个sh具有 cron 环境的会话中

  2. 将您的环境带到 cron

    你可以跳过上面的练习,只是. ~/.profile在你的 cron 工作前做一个,例如

    * * * * * . ~/.profile; your_command
    
  3. 使用屏幕

    以上两种解决方案仍然失败,因为它们提供了一个连接到正在运行的 X 会话的环境,可以访问dbus等。例如,在 Ubuntu 上,nmcli(网络管理器)将在上述两种方法中工作,但在 cron 中仍然失败。

    * * * * * /usr/bin/screen -dm
    

    将以上行添加到 cron,让它运行一次,然后将其关闭。连接到您的屏幕会话 (screen -r)。如果您正在检查屏幕会话是否已创建(使用ps),请注意它们有时是大写的(例如ps | grep SCREEN

    现在甚至nmcli和类似的都会失败。

回答by dimba

You can run:

你可以运行:

env - your_command arguments

This will run your_command with empty environment.

这将在空环境下运行 your_command。

回答by tcurdt

Depending on the shell of the account

取决于帐户的外壳

sudo su
env -i /bin/sh

or

或者

sudo su
env -i /bin/bash --noprofile --norc

From http://matthew.mceachen.us/blog/howto-simulate-the-cron-environment-1018.html

来自http://matthew.mceachen.us/blog/howto-simulate-the-cron-environment-1018.html

回答by Mark Stosberg

Answering six years later: the environment mismatch problem is one of the problems solved by systemd"timers" as a cron replacement. Whether you run the systemd "service" from the CLI or via cron, it receives exactly the same environment, avoiding the environment mismatch problem.

六年后回答:环境不匹配问题是systemd“定时器”作为cron替代解决的问题之一。无论您是从 CLI 还是通过 cron 运行 systemd“服务”,它都会接收完全相同的环境,避免环境不匹配问题。

The most common issue to cause cron jobs to fail when they pass manually is the restrictive default $PATHset by cron, which is this on Ubuntu 16.04:

导致 cron 作业在手动传递时失败的最常见问题是 cron$PATH设置的限制性默认值,这在 Ubuntu 16.04 上是这样的:

"/usr/bin:/bin"

By contrast, the default $PATHset by systemdon Ubuntu 16.04 is:

相比之下,Ubuntu 16.04 上的默认$PATH设置systemd是:

"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

So there's already a better chance that a systemd timer is going to find a binary without further hassle.

因此,systemd 计时器更有可能轻松找到二进制文件。

The downside with systemd timers, is there's a slightly more time to set them up. You first create a "service" file to define what you want to run and a "timer" file to define the schedule to run it on and finally "enable" the timer to activate it.

systemd 计时器的缺点是设置它们的时间稍微多一点。您首先创建一个“服务”文件来定义要运行的内容,并创建一个“计时器”文件来定义运行它的时间表,最后“启用”计时器以激活它。

回答by Jens Carlberg

Create a cron job that runs env and redirects stdout to a file. Use the file alongside "env -" to create the same environment as a cron job.

创建一个运行 env 并将标准输出重定向到文件的 cron 作业。将文件与“env -”一起使用以创建与 cron 作业相同的环境。

回答by Randy Proctor

Don't forget that since cron's parent is init, it runs programs without a controlling terminal. You can simulate that with a tool like this:

不要忘记,因为 cron 的父级是 init,它在没有控制终端的情况下运行程序。您可以使用这样的工具来模拟:

http://libslack.org/daemon/

http://libslack.org/daemon/

回答by Paused until further notice.

By default, cronexecutes its jobs using whatever your system's idea of shis. This could be the actual Bourne shell or dash, ash, kshor bash(or another one) symlinked to sh(and as a result running in POSIX mode).

默认情况下,cron使用系统的任何想法来执行其作业sh。这可能是实际的 Bourne shell 或dash, ash,kshbash(或另一个)符号链接到sh(并因此在 POSIX 模式下运行)。

The best thing to do is make sure your scripts have what they need and to assume nothing is provided for them. Therefore, you should use full directory specifications and set environment variables such as $PATHyourself.

最好的办法是确保你的脚本有它们需要的东西,并假设没有为它们提供任何东西。因此,您应该使用完整的目录规范并设置环境变量,例如您$PATH自己。

回答by four43

Another simple way I've found (but may be error prone, I'm still testing) is to source your user's profile files before your command.

我发现的另一种简单方法(但可能容易出错,我仍在测试中)是在执行命令之前获取用户的配置文件。

Editing a /etc/cron.d/ script:

编辑 /etc/cron.d/ 脚本:

* * * * * user1 comand-that-needs-env-vars

Would turn into:

会变成:

* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars

Dirty, but it got the job done for me. Is there a way to simulate a login? Just a command you could run? bash --logindidn't work. It sounds like that would be the better way to go though.

脏,但它为我完成了工作。有没有办法模拟登录?只是一个你可以运行的命令?bash --login没有用。听起来这将是更好的方法。

EDIT: This seems to be a solid solution: http://www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/

编辑:这似乎是一个可靠的解决方案:http: //www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/

* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l