有时候手工执行Python脚本跑的好好的,但是部署到Linux的crontab中后,就会遇到一些问题,最近终于有空整理一下这方面的内容,其实也是自己也踩了一些别人踩过的坑!这里仅仅列举个人遇到的一些小问题,经验和精力问题,不能面面俱到,仅总结一下自己遇到的这些问题。

环境变量问题

 

cron中的环境变量和系统的环境变量是不一样的,我们可以通过设置定时脚本将cron中的环境变量打印出来,然后一对比,你就能发现差异

* * * * * env > /tmp/env.txt

如果你Python脚本中要获取环境变量的话,那么部署到Crontab作业后就要小心了,很有可能手工运行脚本是正常的,但是部署到Crontab后运行就不正常了,如下所示,我们构造这样一个测试脚本crontab_env_test.py

#!/usr/bin/python

# -*- coding: utf-8 -*-

 

import logging

import os.path

import os

import base64

 

 

 

# 第一步,创建一个logger

logger = logging.getLogger()

logger.setLevel(logging.DEBUG)  # Log等级开关

# 第二步,创建一个handler,用于写入日志文件

log_path = '/home/konglb/logs/'

log_name = log_path + 'kerry_test.log'

logfile = log_name

file_handler = logging.FileHandler(logfile, mode='a+')

file_handler.setLevel(logging.ERROR)  # 输出到file的log等级的开关

# 第三步,定义handler的输出格式

formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")

file_handler.setFormatter(formatter)

# 第四步,将handler添加到logger里面

logger.addHandler(file_handler)

# 如果需要同時需要在終端上輸出,定義一個streamHandler

print_handler = logging.StreamHandler()  # 往屏幕上输出

print_handler.setFormatter(formatter)  # 设置屏幕上显示的格式

logger.addHandler(print_handler)

 

 

db_user=os.environ.get('my_env')

print(db_user)

logger.error(db_user)

如下所示,手工执行该脚本,就会往/home/konglb/logs/kerry_test.log中写入环境变量my_env的值(/etc/profile中设置了export my_env=kerry )

# /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py

kerry

2019-08-20 20:20:18,293 - crontab_env_test.py[line:30] - ERROR: kerry

然后我们配置crontab后,如下所示,通过刷新日志观察其获取环境变量my_env的值

# crontab -l

*/1 * * * *  /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py

如下截图所示,你会看到在Crontab中运行的Python脚本根本没有获取到环境变量my_env的值

# tail -60f kerry_test.log 

2019-08-20 20:20:18,293 - crontab_env_test.py[line:30] - ERROR: kerry

2019-08-20 20:22:02,337 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:23:01,533 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:24:01,682 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:25:01,832 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:26:01,103 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:27:01,243 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:28:01,397 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:29:01,543 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:30:01,680 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:31:01,998 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:32:01,223 - crontab_env_test.py[line:30] - ERROR: None

2019-08-20 20:33:01,369 - crontab_env_test.py[line:30] - ERROR: Non

那么要如何解决这个问题呢,如下所示,在执行Python脚本时,获取/etc/profile中的系统变量(不同平台或不同环境有所区别)

*/1 * * * * source /etc/profile && /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py

还有一种方案,就是使用shell包裹Python脚本,如下所示:

# more kerry.sh 

 

#!/bin/bash

 

source /etc/profile

 

/usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py

*/1 * * * *    /home/konglb/python/kerry.sh

 

相对路径问题

 

把上面的脚本修改一下,使用相对路径,如下所示,然后crontab作业运行时就会报错

#!/usr/bin/python

# -*- coding: utf-8 -*-

 

import logging

import os.path

import os

import base64

 

 

 

# 第一步,创建一个logger

logger = logging.getLogger()

logger.setLevel(logging.DEBUG)  # Log等级开关

# 第二步,创建一个handler,用于写入日志文件

#log_path = '/home/konglb/logs/'

log_path = os.path.dirname(os.getcwd()) + '/logs/'

log_name = log_path + 'kerry_test.log'

logfile = log_name

file_handler = logging.FileHandler(logfile, mode='a+')

file_handler.setLevel(logging.ERROR)  # 输出到file的log等级的开关

# 第三步,定义handler的输出格式

formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")

file_handler.setFormatter(formatter)

# 第四步,将handler添加到logger里面

logger.addHandler(file_handler)

# 如果需要同時需要在終端上輸出,定義一個streamHandler

print_handler = logging.StreamHandler()  # 往屏幕上输出

print_handler.setFormatter(formatter)  # 设置屏幕上显示的格式

logger.addHandler(print_handler)

 

 

db_user=os.environ.get('my_env')

print(db_user)

logger.error(db_user)

其实切换到其它路径后,手工执行该脚本也会报错误,因为相对路径的设置,导致一些逻辑错误出现,如下所示,所以如果要部署为Crontab作业的Python脚本,最好使用绝对路径,避免出现这个问题。

# pwd

/root

# /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py

Traceback (most recent call last):

  File "/home/konglb/python/crontab_env_test.py", line 19, in <module>

    file_handler = logging.FileHandler(logfile, mode='a+')

  File "/usr/local/lib/python3.6/logging/__init__.py", line 1031, in __init__

    StreamHandler.__init__(self, self._open())

  File "/usr/local/lib/python3.6/logging/__init__.py", line 1060, in _open

    return open(self.baseFilename, self.mode, encoding=self.encoding)

FileNotFoundError: [Errno 2] No such file or directory: '//logs/kerry_test.log'

另外,像密码过期导致crontab不执行作业(Linux账号密码过期会导致crontab作业不能执行)这样的案例也遇到过,不过这个与Python脚本无关系,如果遇到相关问题,可以从Why-Cronjob-Not-Work这篇文章介绍的这几个方面去思考、分析判断。

 

 

参考资料:

https://www.tony-yin.site/2018/10/29/Why-Crontab-Not-Work/

crontab中部署Python脚本注意事项的更多相关文章

  1. mac上使用crontab周期性执行python脚本

    这个月买了本书<Linux系统命令及Shell脚本实践指南>, 看到了一个周期性执行任务cron.顿时产生一个想法: mac上有这种机制么? 加上自己也在15年下半年也学了点python脚 ...

  2. C++中调用Python脚本

    C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库, 需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了 先看Python的代码 代 ...

  3. Delphi中使用python脚本读取Excel数据

    Delphi中使用python脚本读取Excel数据2007-10-18 17:28:22标签:Delphi Excel python原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...

  4. nginx tomcat 自动部署python脚本【转】

    #!/usr/bin/env python #--coding:utf8-- import sys,subprocess,os,datetime,paramiko,re local_path='/ho ...

  5. Linux系统crontab定时调度Python脚本

    Linux系统crontab定时调度Python脚本 一.Python脚本随Linux开机自动运行 #Python脚本:/home/edgar/auto.py #用root权限编辑以下文件:/etc/ ...

  6. C++中调用Python脚本(转载)

    转载▼ 标签: 杂谈 C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库,需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了先看Py ...

  7. 使用shell程序备份crontab中的.sh脚本文件

    需求 线上环境有一些定时脚本(用crontab -l可查看当前用户的),有时我们可能会改这些定时任务的脚本内容.为避免改错无后悔药,需用shell实现一个程序,定时备份crontab中的.sh脚本文件 ...

  8. crontab定时运行python脚本访问MySQL遇到问题

    最近写了一个python脚本来定时备份MySQL数据库.具体实现如下: 1)python脚本中使用os.system("mysqldump -h127.0.0.1 -uroot -ppass ...

  9. crontab中运行python程序出错,提示ImportError: No module named解决全过程

    将一个python脚本放入crontab执行时,提示如下错:ImportError: No module named hashlib但是在shell中直接执行时没有任何问题,google之后,得到线索 ...

随机推荐

  1. Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type ... 错误的理解和改正

    No enclosing instance of type SomeClass is accessible. Must qualify the allocation with an enclosing ...

  2. WordPress新用户注册时提示“您的密码重设链接无效”

    在使用Wordpress密码找回功能及新用户注册邮件中的重置密码链接时,Wordpress提示“您的密码重设链接无效,请在下方请求新链接.”.“该key似乎无效”.“invalid key”. 这个其 ...

  3. Linux上编译安装PHP

    这篇文章主要介绍了关于Linux上编译安装PHP,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 之前在服务器上编译安装了PHP运行环境,但是安装完过了一段时间就差不多忘记了,只是零零星 ...

  4. python pytesseract——3步识别验证码的识别入门

    验证码识别是个大工程,但入门开始只要3步.需要用到的库PIL.pytesserac,没有的话pip安装.还有一个是tesseract-ocr 下载地址:https://sourceforge.net/ ...

  5. Python内置函数之enumerate() 函数

    enumerate() 函数属于python的内置函数之一: python内置函数参考文档:python内置函数 转载自enumerate参考文档:python-enumerate() 函数 描述 e ...

  6. 【mybatis】1mybatis下载、配置与初步使用

    一.mybatis历史: 额,学习一门新事物时了解一下它的历史能在脑中形成一个大致的轮廓...进入正题... mybatis以前叫做ibatis,ibatis是Apache旗下的产品,在2010年时g ...

  7. 【Java】用Freemarker完美导出word文档(带图片)

    Java  用Freemarker完美导出word文档(带图片) 前言 最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题. ...

  8. 你真的懂Spring Java Config 吗?Full @Configuration vs lite @Bean mode

    Full @Configuration和lite @Bean mode 是 Spring Java Config 中两个非常有意思的概念. 先来看一下官方文档关于这两者的相关内容: The @Bean ...

  9. Android 横竖屏切换生命周期

    默认情况下,屏幕会旋转并且会重新走生命周期. 1. 屏幕不旋转   在AndroidManifest文件中的对应Activity中配置android:screenOrientation=”landsc ...

  10. spring配置文件默认名称及位置,ContextLoaderListener监听器作用

    spring在web.xml中的配置 由于spring需要启动容器才能为其他框架提供服务,而web应用程序的入口是由web服务器控制的,因此无法在main()方法中通过创建ClassPathXmlAp ...