BASH:如何仅抓取由多个 space 分隔的列?

BASH: How do I grab columns that are separated by more than one space only?

我试图从 protonvpn s 的输出中获取 select 值,但我无法获得正确的值,因为某些单词之间有 space。如果 多个 连续 space,我只想拆分值。我也只对接收第二列中的值感兴趣。

protonvpn s 产生(例如)

的输出
Status:       Connected
Time:         0:34:07
IP:           888.888.888.888
Server:       CH-CA#1
Features:     Secure-Core
Protocol:     TCP
Kill Switch:  Enabled
Country:      United States
City:         None
Load:         34%
Received:     4.43 MB
Sent:         1.17 MB

如果我尝试 vpn=$(protonvpn s | column -s '\t' -t | awk '{print }' ) ; echo "$vpn" 产生:

a
0:27:57
162.253.71.24
CH-CA#1
ures:
ocol:
Swi
ry:
y:
29%
3.33
:

如果我尝试 vpn=$(protonvpn s | column -s ' ' -t | awk '{print }' ) ; echo "$vpn" 会产生:

Connected
0:42:02
162.253.71.24
CH-CA#1
Secure-Core
TCP
Switch:
United
None
34%
4.75
1.32

我还尝试用破折号 (-) 替换单个 spaces ' ' 由:

vpn=$(protonvpn s)
vpn_parsed=${vpn// /-}
echo "$vpn_parsed"

但它会替换所有 space,而不是单词之间的单个 space:

Status:-------Connected
Time:---------0:47:47
IP:-----------162.253.71.24
Server:-------CH-CA#1
Features:-----Secure-Core
Protocol:-----TCP
Kill-Switch:--Enabled
Country:------United-States
City:---------None
Load:---------34%
Received:-----4.92-MB
Sent:---------1.42-MB

然后我似乎无法抓取任何以破折号作为分隔符的列:

vpn_out="$vpn_parsed" | column -s '-' -t | awk '{print }'
echo "$vpn_out"

// Produces no output

我期望并希望输出为:

Connected
0:34:07
888.888.888.888
CH-CA#1
Secure-Core
TCP
Enabled
United States
None
34%
4.43 MB
1.17 MB

有人可以帮我解决这个问题吗?我不是一个非常高级的 Bash 用户,我似乎根本无法让它工作。我不反对用破折号或其他字符替换单词(如 United States)之间的单个 space,但我确实需要删除第一列和额外的白色 space。

知道我需要这个输出在一个数组中,由每行分隔,而不是 space。这样我就可以提取值,比如国家,像这样:

echo ${vpn_arr[7]

// Outputs "United States"

您可以使用 sed 而不是 awk:

protonvpn s | sed -r 's/\S+\s*//'

想法是删除第一个空格之前的所有字符,然后再删除空格。

\S+     # Any non-whitespace character, repeated one or more
\s*     # Any white-space character, repeated one or more

使用 cat file 代替我没有的 protonvpn s

$ declare -A arr="( $(cat file | awk '{tag=val=[=10=]; sub(/:.*/,"",tag); sub(/[^:]+:[[:space:]]*/,"",val); printf " [7%s7]=7%s7", tag, val}') )"

$ declare -p arr
declare -A arr=([Sent]="1.17 MB" [Features]="Secure-Core" [Country]="United States" ["Kill Switch"]="Enabled" [Server]="CH-CA#1" [Load]="34%" [Received]="4.43 MB" [IP]="888.888.888.888" [Protocol]="TCP" [Time]="0:34:07" [City]="None" [Status]="Connected" )

$ for i in "${!arr[@]}"; do echo "$i --> ${arr[$i]}"; done
Sent --> 1.17 MB
Features --> Secure-Core
Country --> United States
Kill Switch --> Enabled
Server --> CH-CA#1
Load --> 34%
Received --> 4.43 MB
IP --> 888.888.888.888
Protocol --> TCP
Time --> 0:34:07
City --> None
Status --> Connected

$ echo "${arr[Country]}"
United States

$ echo "${arr[Received]}"
4.43 MB

$ echo "${arr[Kill Switch]}"
Enabled
vpn=$(protonvpn s | sed 's/^.*: *//' ) ; echo "$vpn"

应该可以解决问题,它会替换 (s/) 从行首 (^.*) 开始的所有内容,包括“:”之后的任意数量的空格 (*),没有任何内容 (//)。

使用 sed 您可以删除每行的开头,直到遇到 : 加上以下 space 个字符:

protonvpn s | sed 's/^[^:]*: *//'
  • s/ 替换
  • ^匹配行首
  • [^:]* 匹配任何非: 字符
  • : 匹配文字 :
  • * 匹配任何 space 个字符
  • // 什么都不替换

要将输出存储到数组中,您可以使用 mapfile:

$ mapfile -t vpn_arr <<< $(protonvpn s | sed 's/^[^:]*: *//')
$ echo "${vpn_arr[7]}"
United States

你可以使用cut命令:

vpn=$(protonvpn s | cut -d':' -f 2,3,4)

cut命令通过指定的分隔符(-d 选项)切割字符串,-f 选项指定要return 的子字符串。由于 protonvpn s 输出的第二行是 Time: 0:34:07 我们需要将 -f 选项设置为 2,3,4 以吞噬所有部分。