包含 perl 元素的 sh 脚本不会通过 crontab 产生与手动执行相同的输出

包含 perl 元素的 sh 脚本不会通过 crontab 产生与手动执行相同的输出

我尝试将其发布在 Stackexchange 上,但我认为我可能有更多机会在这里得到正确答案,因为它非常特定于 Linux。我有一个 sh 脚本,它更新 csv 中的数据,然后从 sh 脚本中运行 perl 脚本 ($match),该脚本匹配两个 csv 文件之间的数据,并使用匹配结果填充文件 $matches。我只会显示脚本末尾的一个片段,因为只有这一点与问题相关:

#!/bin/sh
export PATH="/opt/bin:/opt/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin:/usr/local/sbin:/usr/local/bin"

match=/home/perl_experiments/newitems/match.pl       
matches=/home/perl_experiments/newitems/matches.txt


/usr/bin/perl $match > $matches

if [[ -s $matches ]] ; then
    date >> $log
    echo "matches has data." >> $log
    $sendmail
else
    date >> $log                  
    echo "matches is empty." >> $log
    exit                              
fi

编辑:这是 $match 脚本

#!/usr/bin/perl                                                                                                                                                                              

my @csv2 = ();                                                                                                                                                                               
open CSV2, "<csv2" or die;                                                                                                                                                                   
@csv2=<CSV2>;                                                                                                                                                                                
close CSV2;                                                                                                                                                                                  

my %csv2hash = ();                                                                                                                                                                           
for (@csv2) {                                                                                                                                                                                
  chomp;                                                                                                                                                                                     
  my ($title) = $_ =~ /^.+?,\s*([^,]+?),/; #/ match the title                                                                                                                                
  $csv2hash{$_} = $title;                                                                                                                                                                    
}                                                                                                                                                                                            

open CSV1, "<csv1" or die;                                                                                                                                                                   
while (<CSV1>) {                                                                                                                                                                             
  chomp;                                                                                                                                                                                     
  my ($title) = $_ =~ /^.+?,\s*([^,]+?),/; #/ match the title                                                                                                                                
    my %words;                                                                                                                                                                               
    $words{$_}++ for split /\s+/, $title;    #/ get words                                                                                                                                    
    ## Collect unique words                                                                                                                                                                  
    my @titlewords = keys(%words);                                                                                                                                                           
  my @new;                          #add exception words which shouldn't be matched                                                                                                          
  foreach my $t (@titlewords){                                                                                                                                                               
        push(@new, $t) if $t !~ /^(and|the|to|uk)$/i;                                                                                                                                        
  }                                                                                                                                                                                          
  @titlewords = @new;                                                                                                                                                                        
  my $desired = 5;                                                                                                                                                                           
  my $matched = 0;                                                                                                                                                                           
  foreach my $csv2 (keys %csv2hash) {                                                                                                                                                        
    my $count = 0;                                                                                                                                                                           
    my $value = $csv2hash{$csv2};                                                                                                                                                            
    foreach my $word (@titlewords) {                                                                                                                                                         
            my @matches   = ( $value=~/\b$word\b/ig );                                                                                                                                       
            my $numIncsv2 = scalar(@matches);                                                                                                                                                
            @matches      = ( $title=~/\b$word\b/ig );                                                                                                                                       
            my $numIncsv1 = scalar(@matches);                                                                                                                                                
            ++$count if $value =~ /\b$word\b/i;                                                                                                                                              
            if ($count >= $desired || ($numIncsv1 >= $desired && $numIncsv2 >= $desired)) {                                                                                                  
                $count = $desired+1;                                                                                                                                                         
                last;                                                                                                                                                                        
            }                                                                                                                                                                                
    }                                                                                                                                                                                        
    if ($count >= $desired) {                                                                                                                                                                
      print "$csv2\n";                                                                                                                                                                       
      ++$matched;                                                                                                                                                                            
    }                                                                                                                                                                                        
  }                                                                                                                                                                                          
  print "$_\n\n" if $matched;                                                                                                                                                                
}                                                                                                                                                                                            
close CSV1;                                                                                                                                                                                  
~           

现在,我特意在 2 个 csv 中留下了一些匹配的数据来测试脚本。当我手动运行脚本时,它按预期工作,并且我在 $log 文件中收到消息“匹配有数据”。但是,当它从 crontab 运行时(以 root 身份运行,就像我手动运行它一样),它不会在 $matches- 中生成任何数据,并且 $log 文件条目状态为“matches 为空”。

这是我的 crontab 条目,它肯定会运行脚本,只是不会产生预期的输出:

*/10    09-21   *       *       1,2,3,4,5       root    /home/perl_experiments/newitems/newitems.sh

所以我的问题是,为什么会发生这种情况,我可以修改什么来确保 crontab 执行与我的手动执行相同?这是否与 crontab 在 sh 脚本内运行 perl 脚本时出现问题有关?

正如我所说,当手动运行时,它完全符合我的预期,但是当运行我的 crontab 时,不会产生任何匹配项。欢迎提出建议。

答案1

你的 perl 脚本有

open CSV2, "<csv2" or die;
...
open CSV1, "<csv1" or die;

这些文件位于哪里? cron 的当前目录是用户的主目录。如果文件位于“newitems”目录中,则必须先到cd那里。

确保您没有对程序中的环境做出任何其他假设。

我发现这是一个在 crontab 中启用一次的方便命令:

#* * * * * { date; pwd; echo "env:"; env; echo "set:"; set; } > ~/cron.env

@Otheus 的一个很好的观点:

if ! /usr/bin/perl "$match" > "$matches"; then
    status=$?
    echo "$match script returned unsuccessfully"
    exit $status
fi

相关内容