Extração seletiva de dados

2

Eu tenho o seguinte bloco de dados em um arquivo txt:

Informatica(r) PMCMD, version [9.5.1 HotFix4], build [313.0217], SOLARIS 64-bit 
Copyright (c) Informatica Corporation 1994 - 2014   
All Rights Reserved. 

Invoked at Wed Dec 30 11:13:42 2015 

Connected to Integration Service: [TEST_Integration_Service].   
Integration Service status: [Running]   
Integration Service startup time: [Sun Dec 27 06:37:32 2015]  
Integration Service current time: [Wed Dec 30 11:13:42 2015]  
Folder: [ALS_DIM]  
Workflow: [wf_ld_als_dim] version [1].  
Workflow run status: [Scheduled]  
Workflow run error code: [0]  
Workflow run id [0].  
Schedule time: [Wed Dec 30 19:00:00 2015]  
Workflow run type: [Schedule]  
Run workflow as user: [Administrator]  
Run workflow with Impersonated OSProfile in domain: []  
Integration Service: [TEST_Integration_Service]  
Folder: [ALS_FACT]  
Workflow: [wf_s_m_ld_interchanges_detail_log] version [1].  
Workflow run status: [Scheduled]  
Workflow run error code: [0]  
Workflow run id [0].  
Schedule time: [Mon Jan 04 16:30:00 2016]  
Workflow run type: [Schedule]  
Run workflow as user: [Administrator]  
Run workflow with Impersonated OSProfile in domain: []  
Integration Service: [TEST_Integration_Service]  
Folder: [ALS_PRD]  
Workflow: [wf_maint_service_fields] version [1].  
Workflow run status: [Scheduled]  
Workflow run error code: [0]  
Workflow run id [0].  
Schedule time: [Thu Dec 31 07:10:00 2015]  
Workflow run type: [Schedule]  
Run workflow as user: [Administrator]  
Run workflow with Impersonated OSProfile in domain: []  
Integration Service: [TEST_Integration_Service]  
Number of scheduled workflows on this Integration Service: [3]  
Disconnecting from Integration Service  

Eu preciso extrair dados em outro arquivo de texto de forma que apenas o nome da pasta, o nome do fluxo de trabalho, o status de execução do fluxo de trabalho, o horário agendado e os nomes dos serviços de integração sejam extraídos - nessa ordem - para cada recorrência.

Por exemplo:

Insert into <tablename> values('ALS_DIM', 'wf_ld_als_dim', 'Scheduled', 'Wed Dec 30 19:00:00 2015', 'TEST_Integration_Service')

Isso deve ser extraído para o primeiro conjunto e assim por diante.

Eu desenvolvi um script específico para os 3 conjuntos de dados, mas deve ser tal que o script possa ser executado para qualquer número de conjuntos de dados.

Eu tenho conhecimento preliminar sobre scripts de shell, por isso seria ótimo obter alguma ajuda sobre isso.

    
por NA2003 12.01.2016 / 12:22

2 respostas

1

Uma abordagem Perl:

$ perl -lne 'if(/^(Folder|Workflow|Workflow.*?status|Sched.*time|Integration Service):.*?\[([^][]+)/){++$k%5==0 ? print "$2"  : printf "%s,",$2}' file
ALS_DIM, wf_ld_als_dim, Scheduled, Wed Dec 30 19:00:00 2015, TEST_Integration_Service
ALS_FACT, wf_s_m_ld_interchanges_detail_log, Scheduled, Mon Jan 04 16:30:00 2016, TEST_Integration_Service
ALS_PRD, wf_maint_service_fields, Scheduled, Thu Dec 31 07:10:00 2015, TEST_Integration_Service

Ou menos condensado:

$ perl -lne '
 if(/^                       ## Match the beginning of the line
     (                       ## 1st capturing group: $1
      Folder               | ## The various things we want to match
      Workflow             | 
      Workflow.*?status    |
      Sched.*time          |
      Integration\s*Service
      ):                     ## Only if they are followed by a :
      .*?\[
      (                      ## 2nd caprturing group: $2.
        [^][]+               ## The longest string of non-] or [
      )/x                    ## The x allows writing multiline regexes          
    )
{                            ## If this line matches...
    $k=$k+1;                   ## Increment the counter $k by one
    if($k%5==0){               ## If the current value of $k is a multiple of 5.
      print "$2"               ## Print the 2nd captured group and a newline.
    }                          ## The newline is automatically added by the -l. 

    else{
      printf "%s,",$2         ## For other lines, just print with no newline.
    }
}' file
ALS_DIM, wf_ld_als_dim, Scheduled, Wed Dec 30 19:00:00 2015, TEST_Integration_Service
ALS_FACT, wf_s_m_ld_interchanges_detail_log, Scheduled, Mon Jan 04 16:30:00 2016, TEST_Integration_Service
ALS_PRD, wf_maint_service_fields, Scheduled, Thu Dec 31 07:10:00 2015, TEST_Integration_Service

Para adicionar o Insert ... , basta passar por um simples sed :

$ perl -lne 'if(/^(Folder|Workflow|Workflow.*?status|Sched.*time|Integration Service):.*?\[([^][]+)/){++$k%5==0 ? print "$2"  : printf "%s,",$2}' file | 
    sed "s/^/Insert into <tablename> values('/; s/,/','/g; s/$/')/"
Insert into <tablename> values("ALS_DIM","wf_ld_als_dim","Scheduled","Wed Dec 30 19:00:00 2015","TEST_Integration_Service")
Insert into <tablename> values("ALS_FACT","wf_s_m_ld_interchanges_detail_log","Scheduled","Mon Jan 04 16:30:00 2016","TEST_Integration_Service")
Insert into <tablename> values("ALS_PRD","wf_maint_service_fields","Scheduled","Thu Dec 31 07:10:00 2015","TEST_Integration_Service")

O sed executa três operadores de substituição:

  • s/^/Insert into <tablename> values("/ : ^ é o começo da linha. Portanto, s/^/foo/ simplesmente insere foo no início da linha. Aqui, está inserindo nsert into <tablename> values(" .
  • s/,/','/g : substitua todas as vírgulas ( s///g ) por ',' .
  • s/$/")/' : $ é o final da linha, então isso adicionará )" no final.
por 12.01.2016 / 14:03
2

A sed solution ...

sed -ne'/^Folder: *\[/!{'                                     \
         -e'/^Workflow\( run status\)\{0,1\}: *\[/!{'         \
              -e'/^Schedule time: *\[/!{'                     \
                   -e'/^Integration Service: *\[/!d'          \
    -e\} -e\} -e\} -e"s//'/"      -e"s/\].*/'/"  -e'H;x'      \
                   -e'/ .*\n.*/h' -e's///'       -e'x'        \ 
                   -e's//Insert into <tablename> values(&)/'  \
                   -e's/\n//'     -e's//, /gp'
Insert into <tablename> values('ALS_DIM', 'wf_ld_als_dim', 'Scheduled', 'Wed Dec 30 19:00:00 2015', 'TEST_Integration_Service')
Insert into <tablename> values('ALS_FACT', 'wf_s_m_ld_interchanges_detail_log', 'Scheduled', 'Mon Jan 04 16:30:00 2016', 'TEST_Integration_Service')
Insert into <tablename> values('ALS_PRD', 'wf_maint_service_fields', 'Scheduled', 'Thu Dec 31 07:10:00 2015', 'TEST_Integration_Service')

Assim, as primeiras linhas negam correspondências aceitáveis como ...

if ! match ^Folder: *\[
then  if ! match ^Workflow: *\[ or ^Workflow run status: *\[
      then if !  match ^Schedule time: *\[
           then  if !  match ^Integration Service: *\[
                 then  delete
                 fi
           fi
      fi
fi

Assim que uma linha coincide com qualquer na cadeia, a cadeia está quebrada e não é atravessada até o final. Isso significa que a última expressão regular testada para qualquer linha correspondente irá descrever o cabeçalho da linha até o colchete direito. Em um script sed , você pode consultar novamente a expressão regular compilada mais recentemente com o endereço // empty. E eu só s//'/ ubstituto-lo e substituí-lo com a citação de ' em sua saída desejada.

O que resta é toda a informação que você quer apenas mais o contexto à direita após o primeiro ] em cada linha. E assim, eu s/\].*/'/ ubstitute para o seu trailing ' citam a cauda indesejada de cada linha também.

Neste ponto, todas as linhas foram removidas para apenas as partes desejadas, mas elas ainda não foram unidas. Para efetuar isso eu uso o espaço H old que persiste no ciclo de linha. E, assim, anexar uma cópia de cada linha a H old space, e x alterar os buffers de retenção e padrão, e procurar por / .*\n.*/ para um < espaço > seguido por um < newline > - que acontece apenas na próxima linha retida depois de uma linha de data.

Se o padrão for encontrado, eu sobrescrevo h old space com ele e s/// ubstitute away todos do espaço padrão (para deixar em branco para a próxima iteração porque esta é a última linha para este) . O endereço s/// vazio aqui apenas remove o conteúdo de uma linha que corresponda ao espaço < space > + < newline > padrão - e, portanto, somente na última linha de cada iteração uma dessas instruções pode ser bem-sucedida.

Independentemente disso, eu depois e x altero os buffers de retenção e padrão pela última vez, e assim o buffer padrão agora conterá todas as correspondências desta iteração delimitadas pelos caracteres < newline > ou conterá apenas a correspondência mais recente e zero caracteres < newline > . O buffer de retenção neste ponto está vazio se esta for a última linha correspondente para essa iteração, ou então ele contém todas as linhas correspondentes até este ponto, cada uma delas com o prefixo < newline > .

Em seguida, refiro-me novamente à mesma expressão regular e tento substituir todo um espaço de padrão que corresponde a um < space > + < newline > padrão para si mesmo agrupado em Insert into <tablename> values( e um ) .

Por fim, se houver, eu s/// ubstitute para nada o < newline > que está no espaço padrão da última linha correspondente e todos os restantes < newlines > para uma vírgula, em seguida, um < space > cada. Se a s/// ubstitution for bem-sucedida, seus resultados serão p rinted para stdout.

    
por 12.01.2016 / 13:12