Parsing Saída de Comando no Script Bash

1

Eu preciso de um script bash que pegue a saída de um comando shell e analise essa saída para extrair o id e o URL do website para cada linha da tabela que possa ser usada para executar comandos bash adicionais.

Aqui está um exemplo da saída do comando.

+----+-------------------------------+----------------------------------------+---------+
| id | name                          | url                                    | version |
+----+-------------------------------+----------------------------------------+---------+
| 25 | example.com                   | http://www.example.com/                | 3.8     |
| 34 | anotherexample.com            | https://anotherexample.com/            | 3.2     |
| 62 | yetanotherexample.com         | https://yetanotherexample.com/         | 3.9     |
+----+-------------------------------+----------------------------------------+---------+

O pseudocódigo do script seria o seguinte:

$output = 'command --list'
for each row in $output {
    $siteid=extracted_id
    $url=extracted_url

    $process_result = 'new_command $siteid'
    log "$siteid, $url, $process_result" > log.txt
endif

Observe que o ID numérico pode ter mais de dois dígitos.

Alguém é capaz de me dar um ponto de partida sobre como analisar cada linha do comando de saída original e puxar o id e url como variáveis, ignorando as 3 primeiras linhas e a última linha que são a borda da tabela e o cabeçalho?

Eu posso imaginar o resto, é apenas analisar cada linha em que estou preso.

Qualquer sugestão / conselho seria muito apreciada.

Obrigado antecipadamente.

    
por Phill Coxon 26.10.2018 / 01:23

3 respostas

2

Bem-vindo Phill Coxon ,

Método 1

Este script puro parece atender às suas necessidades

#!/usr/bin/env bash
declare id
declare name
declare url
declare version

while read line; do
  if [[ ! ${line} =~ ^[\+\| ]]; then
    if [[ ${line} =~ \|[[:space:]]*([[:digit:]]+)[[:space:]]*\|[[:space:]]+([[:alnum:]\.]+)[[:space:]]+\|[[:space:]]+(https?:\/\/(www\.)?[[:alnum:]]+\.[[:alpha:]]+\/?)[[:space:]]*\|[[:space:]]*([[:digit:]](\.[[:digit:]])?)[[:space:]]*\|  ]]; then
      id="${BASH_REMATCH[1]}"
      name="${BASH_REMATCH[2]}"
      url="${BASH_REMATCH[3]}"
      version="${BASH_REMATCH[5]}"
      echo "${id}:${name}:${url}:${version}"
    fi
  fi
done

Método 2

Você também pode criar uma função bash e usá-la em seu script como segue

#!/usr/bin/env bash
parse_result(){
  local id
  local name
  local url
  local version

  while read line; do
    if [[ ! ${line} =~ ^[\+\| ]]; then
      if [[ ${line} =~ \|[[:space:]]*([[:digit:]]+)[[:space:]]*\|[[:space:]]+([[:alnum:]\.]+)[[:space:]]+\|[[:space:]]+(https?:\/\/(www\.)?[[:alnum:]]+\.[[:alpha:]]+\/?)[[:space:]]*\|[[:space:]]*([[:digit:]](\.[[:digit:]])?)[[:space:]]*\|  ]]; then
        id="${BASH_REMATCH[1]}"
        name="${BASH_REMATCH[2]}"
        url="${BASH_REMATCH[3]}"
        version="${BASH_REMATCH[5]}"
        echo "${id}:${name}:${url}:${version}"
      fi
    fi
  done
}

parse_result < <(cat cmd.out)

Aqui eu uso substituição de processos , mas você pode usar o pipe

Resultado e discussão

Como exemplo, cmd.out é a saída do comando para analisar. No seu caso você tem que substituir cat cmd.out pelo seu comando

resultado 1:

$ cat cmd.out | ./app.bash
25:example.com:http://www.example.com/:3.8
34:anotherexample.com:https://anotherexample.com/:3.2
62:yetanotherexample.com:https://yetanotherexample.com/:3.9

resultado 2:

$ bash app2.bash
25:example.com:http://www.example.com/:3.8
34:anotherexample.com:https://anotherexample.com/:3.2
62:yetanotherexample.com:https://yetanotherexample.com/:3.9
    
por 26.10.2018 / 02:20
1

Enquanto você pode analisar cuidadosamente o texto com o bash, às vezes é mais fácil confiar em uma ferramenta de processamento de texto dedicada, como o awk:

awk -F'|' ' NR > 3 && !/^+--/ { print $2, $3, $4} ' > log.txt

Isso diz ao awk para dividir as linhas em campos baseados em um separador de | ; o código do programa dentro daspas simples é dividido em:

  • NR > 3 && - se o número de registros (linhas) processados até agora for maior que 3 e ...
  • !/^+--/ - ... e se a linha não não começa com +--
  • ... então print campos 2, 3 e 4

... tudo eventualmente redirecionado para o arquivo log.txt .

    
por 26.10.2018 / 20:00
1

Muito obrigado @bioinfornatics e @jeff Schaller - Estou muito agradecido pelo nível de detalhe que vocês forneceram.

Eu usei ambas as suas respostas para a minha solução mostrada abaixo, em que list_command gera a saída da tabela e o process_command é executado em cada ID do site. Eu testei e está funcionando perfeitamente - eu só preciso adicionar o log e estou pronto.

Muito obrigada aos dois!

#!/usr/bin/env bash
parse_result(){
  local id
  local name
  local url
  local version

  while read line; do

          # pull the id, name and url as variables starting from 4th line and ignoring lines starting with +---

          awk -F'|' ' NR > 3 && !/^+--/ { print $2, $3, $4, $5 } ' | while read id name url version

          do
            RESULT="$(process_command $id)"
            echo "result: $RESULT";
            echo "id: $id | name: $name | url: $url | version: $version";
          done
  done
}
parse_result < <(list_command)
    
por 27.10.2018 / 07:38

Tags