BASH - 解析带有特殊字符的字符串
BASH - Parse strings with special characters
目标:我正在尝试创建 docker ps
的交互式版本。基本上,让每一行都是 "menu" 这样用户就可以:启动、停止、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'
您的引用似乎有一些问题,也许可以试试:
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,因为它通常会给你一些关于错误语法的好提示。
如果您想要一个关联数组,其特征是一个矩阵,您的所有 docker ps
字段都可以在 row/column 中访问,您可以使用 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([=10=],"CONTAINER ID")
head[2] = image=index([=10=],"IMAGE")
head[3] = command=index([=10=],"COMMAND")
head[4] = created=index([=10=],"CREATED")
head[5] = status=index([=10=],"STATUS")
head[6] = ports=index([=10=],"PORTS")
head[7] = names=index([=10=],"NAMES")
}
else{
for (i = 1;i < 8;i++) {
if (i!=7){
printf "%s",rtrim(substr([=10=], head[i], head[i+1] - 1 - head[i])) "|"
}
else{
printf "%s",rtrim(substr([=10=], 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
部分,目的是在每个字段之间插入一个|
字符,以便将要注入的数据与|
分隔符[=20]关联数组=]
由于字段内容与字段标题对齐,我们将每个字段名称的索引存储在head
数组中,并根据下一个字段位置提取每个字段裁剪
然后 matrix
是根据最大列数 (7) 构建的。然后可以使用 ${matrix[row,column]}
轻松访问每个 row/column
通常情况...除非您确切知道格式以及如何控制它,否则不要使用 for 循环读取数据:
while IFS="\n" read -r line
do
array+=("$line")
done< <(docker ps)
就我个人而言,我会尝试删除行首的数字(1.、2. 等),因为这样您就可以将其放入 select 中,它会为您提供数字,然后可以用于引用相关项目。
目标:我正在尝试创建 docker ps
的交互式版本。基本上,让每一行都是 "menu" 这样用户就可以:启动、停止、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'
您的引用似乎有一些问题,也许可以试试:
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,因为它通常会给你一些关于错误语法的好提示。
如果您想要一个关联数组,其特征是一个矩阵,您的所有 docker ps
字段都可以在 row/column 中访问,您可以使用 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([=10=],"CONTAINER ID")
head[2] = image=index([=10=],"IMAGE")
head[3] = command=index([=10=],"COMMAND")
head[4] = created=index([=10=],"CREATED")
head[5] = status=index([=10=],"STATUS")
head[6] = ports=index([=10=],"PORTS")
head[7] = names=index([=10=],"NAMES")
}
else{
for (i = 1;i < 8;i++) {
if (i!=7){
printf "%s",rtrim(substr([=10=], head[i], head[i+1] - 1 - head[i])) "|"
}
else{
printf "%s",rtrim(substr([=10=], 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
部分,目的是在每个字段之间插入一个|
字符,以便将要注入的数据与|
分隔符[=20]关联数组=]
由于字段内容与字段标题对齐,我们将每个字段名称的索引存储在head
数组中,并根据下一个字段位置提取每个字段裁剪
然后 matrix
是根据最大列数 (7) 构建的。然后可以使用 ${matrix[row,column]}
通常情况...除非您确切知道格式以及如何控制它,否则不要使用 for 循环读取数据:
while IFS="\n" read -r line
do
array+=("$line")
done< <(docker ps)
就我个人而言,我会尝试删除行首的数字(1.、2. 等),因为这样您就可以将其放入 select 中,它会为您提供数字,然后可以用于引用相关项目。