2017-02-25 109 views
1

目标:我正在尝试创建docker ps的交互式版本。基本上,具有每行是一个“菜单”,使得用户可以:启动,停止,ssh等BASH - 分析带有特殊字符的字符串

实施例:

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命令的每一行,以便我将Container 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' 
+0

我对在循环内部声明有困惑吗?如果它总是'a'数组,为什么要多次声明它?另外,没有看到任何数据(就像其他人一样,我没有安装Docker),这使得很难知道一个好的答案来提供? – grail

+0

请看看:http://www.shellcheck.net/ – Cyrus

+0

@grail - 数据就是你在我的问题的示例块中看到的内容。至于声明声明,我的想法是我正在处理2个数组: 1。行数组 2.每行“列”数组 – aniculescu

回答

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]}

+0

谢谢你@ bertrand-martel!一个非常彻底的解决方案,很高兴看到我的下一个步骤一堆解决在这里。学习如何在bash中实现“简单”概念已经很有趣了 - 我已经在几分钟内在python和php中完成了这项工作,但是bash版本花费了相当长的时间 – aniculescu

+1

也许获得字段标题索引的概念就像'IMAGE' etc ...可以被普遍化,如果你想支持docker swarm中具有不同字段名称的'docker ps',比如'docker service ls'的其他命令。检查[这篇文章](http://stackoverflow.com/questions/42399522/how-to-sort-by-name-docker-service-ls/42401534#42401534) –

+1

当然,'ps'命令是绝对的这个温和的痴迷的开始:) – aniculescu

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,因为它通常会给你一些坏的语法提示。

+0

谢谢;这工作如我所料。不知道壳检查,但它肯定成为这种学习体验的一部分:) – aniculescu

+0

@aniculescu:不客气!检查bash语法的网站实际上是[shellcheck.net](http://shellcheck.net)(无论出于何种原因,我无意中将其连字),尽管看起来你已经想通了:) –

+0

不用担心,我现在拥有它在vim和崇高。但没有太多问题想出了该网站。 – aniculescu

0

平常的故事被访问......不,除非你确切地知道该格式读取数据的循环,以及如何控制它:

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

我个人会尝试从行首(1,2,等)中删除数字,因为这样你就可以将它扔到选择中,它会给你数字,然后可以用它来引用相关的项目。