Назад | Перейти на главную страницу

Анализ вывода команды в сценарии Bash

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

Вот пример вывода команды.

+----+-------------------------------+----------------------------------------+---------+
| 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     |
+----+-------------------------------+----------------------------------------+---------+

Псевдокод для сценария будет примерно таким:

$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

Обратите внимание, что числовой идентификатор может содержать более двух цифр.

Может ли кто-нибудь дать мне отправную точку о том, как анализировать каждую строку исходной команды вывода и извлекать идентификатор и URL-адрес в качестве переменных, игнорируя первые 3 строки и последнюю строку, которые являются границей и заголовком таблицы?

Я могу разобраться в остальном, это просто анализ каждой строки, на которой я застрял.

Будем очень признательны за любые предложения / советы.

Заранее спасибо.

Большое спасибо @bioinfornatics и @jeff Schaller - я очень признателен за уровень детализации, который вы предоставили каждому.

Я использовал оба ваших ответа для своего решения, показанного ниже, где list_command генерирует вывод таблицы, а process_command запускается для каждого идентификатора веб-сайта. Я протестировал его, и он работает отлично - мне просто нужно добавить запись, и все готово.

Спасибо большое вам обоим!

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

Добро пожаловать Фил Коксон,

Способ 1

Этот чистый сценарий bash, кажется, соответствует вашим потребностям

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

Способ 2

Вы также можете создать функцию bash и использовать ее в своем скрипте следующим образом

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

Здесь я использую замена процесса но вы можете использовать трубу

Результат и обсуждение

Например, cmd.out - это вывод команды для анализа. В вашем случае вам необходимо заменить cat cmd.out по твоей команде

результат 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

результат 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

Хотя вы можете тщательно анализировать текст с помощью bash, иногда проще полагаться на специальный инструмент для обработки текста, такой как awk:

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

Это указывает awk разбивать строки на поля на основе разделителя |; программный код внутри одинарных кавычек разбивается как:

  • NR > 3 && - если количество обработанных записей (строк) больше 3 и ...
  • !/^+--/ - ... и если линия не начать с +--
  • ... затем print поля 2, 3 и 4

... все в конечном итоге были перенаправлены на log.txt файл.