Perl要素を含むshスクリプトは、crontabを介して手動で実行したときと同じ出力を生成しません。

Perl要素を含むshスクリプトは、crontabを介して手動で実行したときと同じ出力を生成しません。

私はこれをStackexchangeに公開しようとしましたが、Linuxに限定されているので、ここで正解を得る可能性が高いと思います。 csvのデータを更新するshスクリプトがあり、shスクリプトで2つのcsvファイル間のデータを一致させるperlスクリプト($ match)を実行し、$ 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で実行すると(手動で実行するかのようにルートとして)、$ matches-にデータが生成されず、$ logファイルエントリに「matches isempt」というメッセージが表示されます。

これは間違いなくスクリプトを実行する私のcrontabエントリです。予想される出力は生成されません。

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

私の質問は、なぜこれが起こり、crontabの実行が手動の実行と同じになるように何を変更できますか?これはshスクリプト内でPerlスクリプトを実行するのに問題があるcrontabに関連している可能性がありますか?

私が言ったように、手動で実行すると正確に私が期待どおりに動作しますが、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

関連情報