Разбор AutoSys JIL с помощью Perl

У меня есть задание для разбора файлов AutoSys JIL. Это определение задания JIL, это файл конфигурации, который считывает и запускает планировщик AUTOSYS. Представьте себе файл, отформатированный таким образом, с тысячами определений заданий, подобных приведенному ниже, сложенными друг на друга в одном и том же формате. Все начинается с заголовка и заканчивается часовым поясом.

/* ----------------- COME_AND_PLAY_WITH_US_DANNY ----------------- */

insert_job: COME_AND_PLAY_WITH_US_DANNY   job_type: CMD
command: /bin/bash -ls
machine: capser.com
owner: twins
permission: foo,foo
date_conditions: 1
days_of_week: mo,tu,we,th,fr
start_times: "04:00"
description: "Forever, and ever and ever"
std_in_file: "/home/room217"
std_out_file: "${CASPERSYSLOG}/room217.out"
std_err_file: "${CASPERSYSLOG}/room217.err
alarm_if_fail: 1
profile: "/autosys_profile"
timezone: US/Eastern

Это сценарий. Мне нужно извлечь задание, машину и команду из определения задания, приведенного выше. Это работает нормально, но в конечном итоге я захочу сохранить информацию в каком-то контейнере и отправить ее, пока этот скрипт выводит результаты построчно в терминале. Прямо сейчас я перенаправляю результаты во временный файл.

#!/foo/bar/perl5/core/5.10/exec/bin/perl
use strict;
use warnings;
use File::Basename ;

my($job, $machine, $command)  ;
my $filename = '/tmp/autosys.jil_output.padc';
open(my $fh, '<:encoding(UTF-8)', $filename)
  or die "Could not open file '$filename' $!";
my $count = 0;
while (my $line = <$fh>) {
    #chomp $line;
    if($line =~ /\/\* -{17} \w+ -{17} \*\//) {
    $count = 1; }
    elsif($line =~  /(alarm_if_fail:)/) {
    $count = 0 ; }
    elsif ($count) {
             if ($line =~ m/insert_job: (\w+).*job_type: CMD/) {
             $job = $1   ;
             }
             elsif($line =~ m/command:(.*)/) {
             $command = $1  ;
             }
             elsif($line =~ m/machine:(.*)/) {
             $machine = $1  ;

             print "$job\t $machine\t $command \n ";      
             }
        }


    #sleep 1 ;
   }

Мой вопрос: когда я помещаю оператор print $ job, $ machine $ command в последний оператор elsif, он работает нормально. Однако, когда я помещаю его вне последней инструкции elsif, как в примере ниже, выходные данные дублируются снова и снова - каждая строка дублируется, как четыре-пять раз в выходных данных. Я не понимаю это. Почему я должен поместить оператор print в последний оператор elsif, чтобы скрипт правильно выводил по одной строке за раз?

elsif ( $line =~ m/machine:(.*)/ ) {
    $machine = $1;
}

print "$job\t $machine\t $command \n ";



Переформатирование приведенного выше кода для удобства чтения

#!/foo/bar/perl5/core/5.10/exec/bin/perl

use strict;
use warnings;

use File::Basename;

my ( $job, $machine, $command );
my $filename = '/tmp/autosys.jil_output.padc';

open( my $fh, '<:encoding(UTF-8)', $filename )
        or die "Could not open file '$filename' $!";

my $count = 0;

while ( my $line = <$fh> ) {

    #chomp $line;
    if ( $line =~ /\/\* -{17} \w+ -{17} \*\// ) {
        $count = 1;
    }
    elsif ( $line =~ /(alarm_if_fail:)/ ) {
        $count = 0;
    }
    elsif ( $count ) {

        if ( $line =~ m/insert_job: (\w+).*job_type: CMD/ ) {
            $job = $1;
        }
        elsif ( $line =~ m/command:(.*)/ ) {
            $command = $1;
        }
        elsif ( $line =~ m/machine:(.*)/ ) {
            $machine = $1;
            print "$job\t $machine\t $command \n ";
        }
    }

    # sleep 1;
}

2 ответа

Решение

Как я уже сказал в своем комментарии, пожалуйста, разумно отформатируйте ваш код. Без этого вы заставите людей либо игнорировать ваш вопрос, либо раздражаться, отвечая, как я

  • Давайте предположим, что неопознанный текстовый блок является просто примером вашего ввода

  • Давайте также предположим, что, хотя ваш код отлично работает с вашими примерами данных, в реальных данных есть некоторые блоки данных, которые не работают

  • Кроме того, я предполагаю, что любое значение поля данных, которое содержит пробелы, требует заключенных в кавычки, что делает ваш пример command: /bin/bash -ls неверный и неверный синтаксис

Также убедитесь, что вы дали правильный пример своей проблемы с работающим кодом и данными. Если я выполню код, который вы показываете на примере данных, то все работает нормально, так что у вас за проблема?

Насколько я могу судить, вы хотите отобразить insert_job, machine, а также command поля из каждого блока данных JIL, чьи job_type поле CMD, Это правильно?

Вот мое лучшее предположение: комментарийxxfelixxx верен, и вы просто печатаете все поля, которые собирали каждый раз, когда читаете строку из файла данных

Мое решение состоит в том, чтобы преобразовать каждый блок данных в хеш.

Опасно использовать комментарии для разграничения блоков, и вы не предоставили никакой информации о порядке полей, поэтому я должен предположить, что insert_job поле на первом месте. Это имеет смысл, если файл будет использоваться в качестве списка императивов, но дополнительный job_type поле на той же строке странно. Это подлинный образец ваших данных или другая проблема с вашим примером?

Вот рабочее решение моего воображения вашей проблемы.

#!/foo/bar/perl5/core/5.10/exec/bin/perl

use strict;
use warnings 'all';

my $data = do {
    local $/;
    <DATA>;
};

my @data = grep /:/, split /^(?=insert_job)/m, $data;

for ( @data ) {

    my %data = /(\w+) \s* : \s* (?| " ( [^""]+ ) " | (\S+) )/gx;

    next unless $data{job_type} eq 'CMD';

    print "@data{qw/ insert_job machine command /}\n";
}


__DATA__
/* ----------------- COME_AND_PLAY_WITH_US_DANNY ----------------- */

insert_job: COME_AND_PLAY_WITH_US_DANNY   job_type: CMD
command: /bin/bash -ls
machine: capser.com
owner: twins
permission: foo,foo
date_conditions: 1
days_of_week: mo,tu,we,th,fr
start_times: "04:00"
description: "Forever, and ever and ever"
std_in_file: "/home/room217"
std_out_file: "${CASPERSYSLOG}/room217.out"
std_err_file: "${CASPERSYSLOG}/room217.err
alarm_if_fail: 1
profile: "/autosys_profile"
timezone: US/Eastern

/* ----------------- COME_AND_PLAY_WITH_US_AGAIN_DANNY ----------------- */

insert_job: COME_AND_PLAY_WITH_US_AGAIN_DANNY   job_type: CMD
command: /bin/bash -ls
machine: capser.com
owner: twins
permission: foo,foo
date_conditions: 1
days_of_week: mo,tu,we,th,fr
start_times: "04:00"
description: "Forever, and ever and ever"
std_in_file: "/home/room217"
std_out_file: "${CASPERSYSLOG}/room217.out"
std_err_file: "${CASPERSYSLOG}/room217.err
alarm_if_fail: 1
profile: "/autosys_profile"
timezone: US/Eastern

/* ----------------- NEVER_PLAY_WITH_US_AGAIN_DANNY ----------------- */

insert_job: NEVER_PLAY_WITH_US_AGAIN_DANNY   job_type: CMD
command: /bin/bash -rm *
machine: capser.com
owner: twins
permission: foo,foo
date_conditions: 1
days_of_week: mo,tu,we,th,fr
start_times: "04:00"
description: "Forever, and ever and ever"
std_in_file: "/home/room217"
std_out_file: "${CASPERSYSLOG}/room217.out"
std_err_file: "${CASPERSYSLOG}/room217.err
alarm_if_fail: 1
profile: "/autosys_profile"
timezone: US/Eastern

выход

COME_AND_PLAY_WITH_US_DANNY capser.com /bin/bash
COME_AND_PLAY_WITH_US_AGAIN_DANNY capser.com /bin/bash
NEVER_PLAY_WITH_US_AGAIN_DANNY capser.com /bin/bash

Это решение ksh для преобразования файла JIL в файл, разделенный запятыми, который можно открыть в Excel

#!/usr/bin/ksh

# unix scprit to flatten autorep -q

resetVar()
{
    AIF=""
    AD=""
    AH=""
    BF=""
    BN=""
    BS=""
    BT=""
    COM=""
    COD=""
    DC=""
    DOW=""
    DES=""
    EC=""
    IJ=""
    JL=""
    JT=""
    MAC=""
    MES=""
    MRA=""
    NR=""
    OWN=""
    PER=""
    PRI=""
    PRO=""
    RC=""
    RW=""
    SM=""
    ST=""
    SEF=""
    SOF=""
    TRT=""
    WF=""
    WFMS=""
    WI=""
    LSD=""
    LST=""
    LED=""
    LET=""
    STA=""
    RUN=""
}


writePartToFile()
{
 echo "$AIF;$AD;$AH;$BF;$BN;$BS;$BT;$COM;$COD;$DC;$DOW;$DES;$EC;$IJ;$JL;$JT;$MAC;$MES;$MRA;$NR;$OWN;$PER;$PRI;$PRO;$RC;$RW;$SM;$ST;$SEF;$SOF;$TRT;$WF;$WFMS;$WI" >> $TO_TPM
 #echo "$AIF;$AD;$AH;$BF;$BN;$BS;$BT;$COM;$COD;$DC;$DOW;$DES;$EC;$IJ;$JL;$JT;$MAC;$MES;$MRA;$NR;$OWN;$PER;$PRI;$PRO;$RC;$RW;$SM;$ST;$SEF;$SOF;$TRT;$WF;$WFMS;$WI" 
 resetVar

}

JOB_NAME="flatten JIL"
part1=""
part2=""


#---------------------------------
if test "$1." = "."
then
   echo "Missing first parameter (jil file to flatten)"; 
   exit 1;
fi

if test "$2." = "."
then
   echo "Missing second parameter (resulting flat file)";
 exit 1;
fi

TO_FLATTEN=$1
TO_RESULT=$2
CLE_FILE="lesCles"
CLE_TMP="lesClesTmp"
TO_TPM="tempFichier"
TO_STATUS="statusFichier"

rm $TO_RESULT
rm $CLE_TMP
rm $CLE_FILE
rm $TO_TPM
rm $TO_STATUS

echo 'alarm_if_fail;auto_delete;auto_hold;box_failure;box_name;box_success;box_terminator;command;condition;date_conditions;days_of_week;description;exclude_calendar;insert_job;job_load;job_terminator;machine;max_exit_success;max_run_alarm;n_retrys;owner;permission;priority;profile;run_calendar;run_window;start_mins;start_times;std_err_file;std_out_file;term_run_time;watch_file;watch_file_min_size;watch_interval;last_start_date;last_start_time;last_end_date;last_end_time;status;run' >> $TO_RESULT;
 while read line; do    
    if test "${line#*:}" != "$line"
    then        
      cle="$(echo "$line" | cut -d":" -f 1)"
      #echo "cle = $cle"
      part2="$(echo "$line" | cut -d":" -f 2)"   
      #echo "part2 = $part2"        
      val="$(echo "$part2" | cut -d" " -f 2)"
      #echo "val = $val"    
    fi  
    if test "$cle" = "insert_job"
    then
    #on n'est sur la premiere ligne
        if test "$IJ." = "."
        then
            ;                           
        else          
            if test "$BN." = "."
            then             
             echo $IJ >> $CLE_TMP
            else
             echo $BN >> $CLE_TMP
            fi      
            writePartToFile         
        fi
        IJ=$val
        JT="$(echo "$line" | cut -d":" -f 3)"                   
    else    
    #on n est pas sur le premiere ligne 
        val=$part2
        case $cle in
            alarm_if_fail) AIF=$val;;
            auto_delete) AD=$val;;
            auto_hold) AH=$val;;
            box_failure) BF=$val;;
            box_name) BN=$val;;
            box_success) BS=$val;;
            box_terminator) BT=$val;;
            command) COM=$val;;
            condition) COD=$val;;
            date_conditions) DC=$val;;
            days_of_week) DOW=$val;;
            description) DES=$val;;
            exclude_calendar) EC=$val;;
            insert_job) IJ=$val;;
            job_load) JL=$val;;
            job_terminator) JT=$val;;
            machine) MAC=$val;;
            max_exit_success) MES=$val;;
            max_run_alarm) MRA==$val;;
            n_retrys) NR=$val;;
            '#owner') OWN=$val;;
            permission) PER=$val;;
            priority) PRI=$val;;
            profile) PRO=$val;;
            run_calendar) RC=$val;;
            run_window) RW=$val;;
            start_mins) SM=$val;;
            start_times) ST=$val;;
            std_err_file) SEF=$val;;
            std_out_file) SOF=$val;;
            term_run_time) TRT=$val;;
            watch_file) WF=$val;;
            watch_file_min_size) WFMS=$val;;
            watch_interval) WI=$val;; 
        esac        
    fi

done  < $TO_FLATTEN;
#Traiter derniere occurence
if test "$BN." = "."
then
    echo $IJ >> $CLE_TMP
else
    echo $BN >> $CLE_TMP
fi      
writePartToFile     

echo "Les cles"
cat $CLE_TMP | sort | uniq > $CLE_FILE
cat $CLE_FILE
rm $CLE_TMP

#------------------------------
 while read line; do        
    autorep -J ${line} -w  >> $TO_STATUS;   
done  < $CLE_FILE;
#----------------------------------------
echo " Resultats"
while read line; do
unJob="$(echo "$line" | cut -d";" -f 14)"
details="$(grep -w  "$unJob" "$TO_STATUS" | head -n 1)" 
LSD="$(echo "$details" | awk '{print $2}')"
if test "$LSD" = "-----"
then
    LST=""
    LED="$(echo "$details" | awk '{print $3}')"
    if test "$LED" = "-----"
    then
        LET=""
        STA="$(echo "$details" | awk '{print $4}')"
        RUN="$(echo "$details" | awk '{print $5}')"
    else
        LET="$(echo "$details" | awk '{print $4}')"
        STA="$(echo "$details" | awk '{print $5}')"
        RUN="$(echo "$details" | awk '{print $6}')"
    fi
else
    LST="$(echo "$details" | awk '{print $3}')"
    LED="$(echo "$details" | awk '{print $4}')"
    if test "$LED" = "-----"
    then
        LET=""
        STA="$(echo "$details" | awk '{print $5}')"
        RUN="$(echo "$details" | awk '{print $6}')"
    else
        LET="$(echo "$details" | awk '{print $5}')"
        STA="$(echo "$details" | awk '{print $6}')"
        RUN="$(echo "$details" | awk '{print $7}')"
    fi
fi

echo " ligne= ${line};${LSD};${LST};${LED};${LET};${STA};${RUN}"
echo "${line};${LSD};${LST};${LED};${LET};${STA};${RUN}" >> $TO_RESULT
resetVar
done  < $TO_TPM;
Другие вопросы по тегам