解析 Bash 脚本中的命令输出

解析 Bash 脚本中的命令输出

我需要一个 bash 脚本,它获取 shell 命令的输出并解析该输出以提取表中每一行的 id 和网站 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

请注意,数字 ID 可以超过 2 位数字。

有人能给我一个起点,告诉我如何解析原始输出命令的每一行,并将 id 和 url 作为变量拉出,同时忽略表格边框和标题的前三行和最后一行?

我可以弄清楚其余的部分,只是解析我卡住的每一行。

如有任何建议/意见,我们将不胜感激。

提前致谢。

答案1

欢迎菲尔·考克森

方法 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

答案2

非常感谢@bioinfornatics 和@jeff Schaller——我非常感谢你们提供的详细信息。

我在下面所示的解决方案中使用了你们两个的答案,其中 list_command 生成表格输出,process_command 针对每个网站 ID 运行。我已经测试过了,它运行正常 - 我只需要添加日志记录就可以了。

非常感谢你们俩!

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

答案3

虽然你可以用 bash 仔细解析文本,但有时依赖专用的文本处理工具(如 awk)会更容易:

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

这告诉 awk 根据分隔符将行拆分为字段|;单引号内的程序代码分解如下:

  • NR > 3 &&-- 如果到目前为止处理的记录数(行数)大于 3 并且...
  • !/^+--/-- ... 如果该行确实不是从...开始+--
  • ...然后是print字段 2、3 和 4

...最终全部重定向到log.txt文件。

相关内容