2017-02-25 105 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,等)中刪除數字,因爲這樣你就可以將它扔到選擇中,它會給你數字,然後可以用它來引用相關的項目。