Perl 요소가 포함된 sh 스크립트는 crontab을 통해 수동으로 실행할 때와 동일한 출력을 생성하지 않습니다.

Perl 요소가 포함된 sh 스크립트는 crontab을 통해 수동으로 실행할 때와 동일한 출력을 생성하지 않습니다.

나는 이것을 Stackexchange에 게시하려고 시도했지만 Linux에만 국한된 것이기 때문에 여기에서 정답을 얻을 가능성이 더 높을 것이라고 생각합니다. csv의 데이터를 업데이트하는 sh 스크립트가 있고 sh 스크립트에서 두 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

관련 정보