sh script contendo o elemento perl não produz a mesma saída via crontab que a execução manual

1

Eu tentei postar isso no Stackexchange, mas acho que posso ter mais chance de uma resposta correta aqui, pois é muito específico do Linux. Eu tenho um script sh que atualiza dados em um csv, em seguida, executa um script perl ($ match) de dentro do script sh que corresponde a dados entre dois arquivos csv e preenche o arquivo $ matches com os resultados correspondentes. Eu só vou mostrar um trecho do final do script porque só esse bit é relevante para a pergunta:

#!/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

EDIT: Aqui está o script $ 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;                                                                                                                                                                                  
~           

Agora, deixei deliberadamente alguns dados nos 2 csv que correspondem para testar o script. Quando executo o script manualmente, ele funciona como esperado e recebo a mensagem "correspondências tem dados" no arquivo $ log. No entanto, quando ele é executado a partir do crontab (como root, como quando eu o executo manualmente), ele não produz nenhum dado em $ matches e os estados de entrada dos arquivos de log $ "matches is empty."

Aqui está minha entrada crontab, que definitivamente roda o script, simplesmente não produz a saída esperada:

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

Então, minha pergunta é: por que isso está acontecendo e o que posso corrigir para garantir que as execuções do crontab sejam as mesmas das minhas execuções manuais? É algo a ver com o crontab tendo problemas com a execução de um script perl dentro de um script sh?

Como eu digo quando executado manualmente, ele faz exatamente o que eu esperava, mas quando eu executo o meu crontab, nenhuma correspondência é produzida. Sugestões bem-vindas.

    
por nmh 06.06.2016 / 12:43

1 resposta

3

Seu script perl tem

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

Onde estão esses arquivos? O diretório atual do cron é o diretório inicial do usuário. Se os arquivos estiverem no diretório "newitems", você precisará cd ai primeiro.

Verifique se você não está fazendo nenhuma outra suposição sobre o meio ambiente em seus programas.

Eu acho que este é um comando útil para habilitar no seu crontab uma vez:

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

Um excelente ponto de @Otheus:

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