Perl脚本Cron /环境问题

时间:2019-01-24 17:50:44

标签: linux perl cron

以下Perl脚本从文本文件生成一个.xls文件。它在Linux测试环境中运行良好,但是在通过cron运行时,在生产环境中会生成一个空电子表格(.xls)(cron也可以在测试中运行。)在系统级别设置方面,我们的系统管理员一无所获可能是造成这种现象的原因。在import_data子例程的脚本底部,报告了正确的行数,但没有任何内容写入电子表格,并且在脚本或系统级别均未返回任何错误。我通过perl调试器运行它,但是我的技能不足以交互地观看它填充文件。 cron条目如下所示:

cd <script directory>; cvs2xls input.txt output.xls 2>&1

任何调试技巧,以及可以转发给系统管理员的潜在系统设置,将不胜感激。

#!/usr/bin/perl
use strict;
use warnings;

use lib '/apps/tu01688/perl5/lib/perl5';

use Spreadsheet::WriteExcel;
use Text::CSV::Simple;

BEGIN {
  unshift @INC, "/apps/tu01688/jobs/mayo-expert";
};

my $infile = shift;
usage()  unless defined $infile && -f $infile;
my $parser = Text::CSV::Simple->new;
my @data = $parser->read_file($infile);
my $headers = shift @data;

my $outfile = shift || $infile . ".xls";
my $subject = shift || 'worksheet';

sub usage {
    print "csv2xls infile [outfile] [subject]\n";
    exit;
}

my $workbook = Spreadsheet::WriteExcel->new($outfile);
my $bold = $workbook->add_format();
$bold->set_bold(1);
import_data($workbook, $subject, $headers, \@data);

# Add a worksheet
sub import_data {
    my $workbook  = shift;
    my $base_name = shift;
    my $colums    = shift;
    my $data      = shift;
    my $limit     = shift || 50_000;
    my $start_row = shift || 1;
    my $worksheet = $workbook->add_worksheet($base_name);
    $worksheet->add_write_handler(qr[\w], \&store_string_widths);
    #$worksheet->add_write_handler(qr[\w]| \&store_string_widths);
    my $w = 1;
    $worksheet->write('A' . $start_row, $colums, ,$bold);
    my $i = $start_row;
    my $qty = 0;
    for my $row (@$data) {
        $qty++;
        if ($i > $limit) {
             $i = $start_row;
             $w++;
             $worksheet = $workbook->add_worksheet("$base_name - $w");
             $worksheet->write('A1', $colums,$bold);
        }
        $worksheet->write($i++, 0, $row);
    }
    autofit_columns($worksheet);
    warn "Converted $qty rows.";
    return $worksheet;
}


###############################################################################
###############################################################################
#
# Functions used for Autofit.
#

###############################################################################
#
# Adjust the column widths to fit the longest string in the column.
#
sub autofit_columns {

    my $worksheet = shift;
    my $col       = 0;

    for my $width (@{$worksheet->{__col_widths}}) {

        $worksheet->set_column($col, $col, $width) if $width;
        $col++;
    }
}


###############################################################################
#
# The following function is a callback that was added via add_write_handler()
# above. It modifies the write() function so that it stores the maximum
# unwrapped width of a string in a column.
#
sub store_string_widths {

    my $worksheet = shift;
    my $col       = $_[1];
    my $token     = $_[2];

    # Ignore some tokens that we aren't interested in.
    return if not defined $token;       # Ignore undefs.
    return if $token eq '';             # Ignore blank cells.
    return if ref $token eq 'ARRAY';    # Ignore array refs.
    return if $token =~ /^=/;           # Ignore formula

    # Ignore numbers
    #return if $token =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;

    # Ignore various internal and external hyperlinks. In a real scenario
    # you may wish to track the length of the optional strings used with
    # urls.
    return if $token =~ m{^[fh]tt?ps?://};
    return if $token =~ m{^mailto:};
    return if $token =~ m{^(?:in|ex)ternal:};


    # We store the string width as data in the Worksheet object. We use
    # a double underscore key name to avoid conflicts with future names.
    #
    my $old_width    = $worksheet->{__col_widths}->[$col];
    my $string_width = string_width($token);

    if (not defined $old_width or $string_width > $old_width) {
        # You may wish to set a minimum column width as follows.
        #return undef if $string_width < 10;

        $worksheet->{__col_widths}->[$col] = $string_width;
    }


    # Return control to write();
    return undef;
}


###############################################################################
#
# Very simple conversion between string length and string width for Arial 10.
# See below for a more sophisticated method.
#
sub string_width {

    return length $_[0];
}

2 个答案:

答案 0 :(得分:2)

嗯..不要将链接的命令放在cron中,而是使用外部脚本。无论如何:一些可以帮助您的建议:

调试cron命令

检查邮件!默认情况下,cron会将命令的任何输出邮寄给运行命令的用户。如果没有输出,将没有邮件。如果您希望cron将邮件发送到其他帐户,则可以在crontab文件中设置MAILTO环境变量,例如

MAILTO=user@somehost.tld
1 2 * * * /path/to/your/command

自己捕获输出

1 2 * * *  /path/to/your/command &>/tmp/mycommand.log

将stdout和stderr捕获到/tmp/mycommand.log

查看日志; cron通过syslog记录其操作,具体取决于您的设置,该日志通常转到/var/log/cron/var/log/syslog

如果需要,您可以使用例如过滤cron语句。

grep CRON /var/log/syslog 

现在,我们已经了解了cron的基础知识,文件的位置以及如何使用它们,让我们看一些常见的问题。

检查cron是否正在运行

如果cron没有运行,那么您的命令将不会被调度...

ps -ef | grep cron | grep -v grep

应该给您类似

root    1224   1  0 Nov16 ?    00:00:03 cron

root    2018   1  0 Nov14 ?    00:00:06 crond

如果不重新启动它

/sbin/service cron start

/sbin/service crond start

可能还有其他方法;使用您的发行版提供的内容。

cron在受限环境中运行命令。

可用的环境变量可能非常有限。通常,您只会定义一些变量,例如$LOGNAME$HOME$PATH

需要特别注意的是PATH仅限于/bin:/usr/bin绝大多数“我的cron脚本不起作用”问题是由这种限制性路径引起的。如果您的命令位于其他位置,则可以通过以下几种方法解决此问题:

  1. 提供命令的完整路径。

    1 2 * * * /path/to/your/command
    
  2. 在crontab文件中提供合适的PATH

    PATH=/usr:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

如果您的命令需要其他环境变量,您也可以在crontab文件中定义它们。

cron使用cwd == $ HOME运行您的命令

无论您执行的程序在文件系统上的哪个位置,在cron运行时,该程序的当前工作目录均为用户的主目录。如果您访问程序中的文件,则在使用相对路径时,或者(最好)在任何地方都使用完全限定的路径,都需要考虑到这一点,并避免所有人陷入混乱。

我的crontab中的最后一个命令没有运行

Cron通常要求命令以换行符终止。编辑您的crontab;转到包含最后一个命令的行的末尾并插入新行(按Enter键)。

检查crontab格式

您不能将用户crontab格式的crontab用于/ etc / crontab或/etc/cron.d中的片段,反之亦然。格式化用户的crontab在行的第6位不包含用户名,而系统格式化的crontab包括用户名并以该用户身份运行命令。

我在/ etc / cron中放置了一个文件。{每小时,每天,每周,每月},它没有运行

  • 检查文件名没有扩展名,请参见run-parts
  • 确保文件具有执行权限。
  • 告诉系统执行脚本时要使用的内容(例如,将#!/bin/sh放在顶部)

与约会有关的错误

如果您的日期最近是由用户或系统更新,时区或其他时间更改的,则crontab将开始表现异常,并显示异常的bug,有时可以正常工作,有时不能正常工作。当时间从下面改变时,这是crontab尝试尝试“做您想做的事”的尝试。更改小时后,“分钟”字段将失效。在这种情况下,仅星号将被接受。重新启动cron并重试一次,而无需连接到互联网(因此日期没有机会重置为时间服务器之一)。

百分号再次

为强调有关百分号的建议,下面是cron如何处理百分号的示例:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

将创建包含3行的〜/ cron.out文件

foo
bar
baz

使用date命令时,这尤其具有侵入性。确保逃脱百分号

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"

答案 1 :(得分:0)

非常感谢大家的广泛反馈。我肯定会比我投入的更多。无论如何,我碰到了答案。在我的perl5 lib文件夹中,我发现生产中缺少IO和OLE库。从开发中复制过来的内容可以使一切正常运行。我无法通过常规的调试工作来确定/捕获这一事实,而不是仅仅比较激怒中的目录列表,这表明我必须从这些方面学到更多知识。但是,我有信心,我收到的宝贵反馈将大大帮助我实现这一目标。再次感谢大家。