BASH - 使用特殊字符解析字符串

时间:2017-02-25 17:11:17

标签: bash text-parsing

目标:我尝试创建docker ps的互动版本。基本上,每行都是一个"菜单"这样用户可以:启动,停止,ssh等。

示例:

   CONTAINER ID        IMAGE             COMMAND                  CREATED             STATUS              PORTS                                   NAMES
1. bf4a9c7de6bf        app_1             "docker-php-entryp..."   7 days ago          Up About an hour    443/tcp, 0.0.0.0:80->80/tcp, 9000/tcp   app_1
2. 26195f0764ce        app_2             "sh /var/www/html/..."   10 days ago         Up About an hour    443/tcp, 127.0.0.1:8000->80/tcp         app_2

选择(1/2等)后,会有一个选项菜单,可以对所选容器执行各种操作。

问题:我似乎无法弄清楚如何解析docker ps命令的每一行,以便我将容器ID和其他值作为数组元素。

到目前为止的代码:

list=`docker ps`
IFS=$'\n' array=($list)

for index in ${!array[@]}
do
  declare -a 'a=('"${array[index]}"')'
  printf "%s\n" "${a[@]}"  
done

结果:

CONTAINER
ID
IMAGE
COMMAND
CREATED
STATUS
PORTS
NAMES
/usr/bin/dockersh: array assign: line 9: syntax error near unexpected token `>'
/usr/bin/dockersh: array assign: line 9: `bf4a9c7de6bf        app_1             "docker-php-entryp..."   7 days ago          Up About an hour    443/tcp, 0.0.0.0:80->80/tcp, 9000/tcp   app_1'

3 个答案:

答案 0 :(得分:3)

看起来你引用了一些问题,也许可以试试:

list=$(docker ps)
IFS=$'\n' array=($list)

for index in "${!array[@]}"
do
  declare -a a=("${array[index]}")
  printf "%s\n" "${a[@]}"  
done

如果没有正确引用,你的字符串可能会被重新分割;考虑检查你的shell脚本@ shell-check.net,因为它通常会给你一些关于错误语法的好提示。

答案 1 :(得分:1)

如果您想要一个具有矩阵的关联数组,其中所有docker ps字段都可以在行/列中访问,则可以使用awk在字段之间插入分隔符|。然后将结果导出到单个关联数组中,并根据您期望的列数构建矩阵(例如7):

#!/bin/bash
IFS=$'|'

data=$(docker ps -a | awk '
function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
{
    if (NR == 1) {
        head[1] = index($0,"CONTAINER ID")
        head[2] = image=index($0,"IMAGE")
        head[3] = command=index($0,"COMMAND")
        head[4] = created=index($0,"CREATED")
        head[5] = status=index($0,"STATUS")
        head[6] = ports=index($0,"PORTS")
        head[7] = names=index($0,"NAMES")
    }
    else{
        for (i = 1;i < 8;i++) {
            if (i!=7){
                printf "%s",rtrim(substr($0, head[i], head[i+1] - 1 - head[i])) "|"
            }
            else{
                printf "%s",rtrim(substr($0, head[i], 100)) "|"
            }
        }
        print ""
    }
}')

arr=($data)
max_column=7
row=0
column=0

declare -A matrix

for index in "${!arr[@]}"
do
    matrix[$row,$column]=$(echo "${arr[index]}" | tr -d '\n')
    column=$((column+1))
    if [ $((column%max_column)) == 0 ]; then
        row=$((row+1))
        column=0
    fi
done

echo "first  container ID   is : ${matrix[0,0]}"
echo "second container ID   is : ${matrix[1,0]}"
echo "third  container NAME is : ${matrix[2,6]}"

awk部分中,目的是在每个字段之间插入|字符,以便将数据注入到具有|分隔符的关联数组中

当字段内容与字段标题对齐时,我们将每个字段名称的索引存储在head数组中,并根据下一个字段位置提取每个字段修剪

然后根据最大列数(7)构建matrix。然后可以使用${matrix[row,column]}

轻松访问每个行/列

答案 2 :(得分:0)

常见故事...除非您确切知道格式以及如何控制它,否则不要使用for循环读取数据:

while IFS="\n" read -r line
do
  array+=("$line")
done< <(docker ps)

就我个人而言,我会尝试从行的开头(1.,2。等)中删除数字,因为这样你就可以把它扔进一个选择中它会给你数字,然后可以用它来引用相关的项目