BASH:如何获取仅由多个空格分隔的列?

BASH:如何获取仅由多个空格分隔的列?,bash,awk,stdout,Bash,Awk,Stdout,我试图从protonvpn s的输出中获取选择值,但无法获得正确的值,因为某些单词之间有空格。我只想在有多个连续空格的情况下分割值。我也只对第二列中的值感兴趣 protonvpn s生成的输出(例如) 如果我尝试vpn=$(protonvpn s | column-s'\t'-t | awk'{print$2});echo“$vpn” 产生: a 0:27:57 162.253.71.24 CH-CA#1 ures: ocol: Swi ry: y: 29% 3.33 : Connected

我试图从
protonvpn s
的输出中获取选择值,但无法获得正确的值,因为某些单词之间有空格。我只想在有多个连续空格的情况下分割值。我也只对第二列中的值感兴趣

protonvpn s
生成的输出(例如)

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

a
0:27:57
162.253.71.24
CH-CA#1
ures:
ocol:
Swi
ry:
y:
29%
3.33
:
Connected
0:42:02
162.253.71.24
CH-CA#1
Secure-Core
TCP
Switch:
United
None
34%
4.75
1.32
如果我尝试
vpn=$(protonvpn s | column-s'-t | awk'{print$2}');echo“$vpn”
生成:

a
0:27:57
162.253.71.24
CH-CA#1
ures:
ocol:
Swi
ry:
y:
29%
3.33
:
Connected
0:42:02
162.253.71.24
CH-CA#1
Secure-Core
TCP
Switch:
United
None
34%
4.75
1.32
我还尝试将单个空格
'
替换为破折号
):

vpn=$(protonvpn s)
vpn_parsed=${vpn// /-}
echo "$vpn_parsed"
但它取代了单词之间的所有空格,而不是单个空格:

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 $2}'
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
),但我确实需要删除第一列和额外的空格

可能还需要知道,我将需要一个数组中的输出,由每行分隔,而不是由空格分隔。这样我就可以提取价值观,比如国家,比如:

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文件
代替我没有的
protonvpn s

$ declare -A arr="( $(cat file | awk '{tag=val=$0; sub(/:.*/,"",tag); sub(/[^:]+:[[:space:]]*/,"",val); printf " [\047%s\047]=\047%s\047", 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

应该可以做到这一点,它将从行首(^.*)开始的(s/)全部替换,包括“:”之后的任意数量的空格(*),而不使用(//)。

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

protonvpn s | sed 's/^[^:]*: *//'
  • s/
    替换
  • ^
    匹配行首
  • [^:::]*
    匹配任何非
    字符
  • 匹配文字
  • *
    匹配任何空格字符
  • /
    替换为零
要将输出存储到数组中,可以使用
mapfile

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

$mapfile-t vpn\u arr您可以使用
cut
命令:

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

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

听起来您真正想要的不是第2列,而是除第1列之外的所有列。protovpn选项卡的输出是否分开?如果是这样的话,那就很容易了:
cut-f2-
。如果没有,也许您需要一些
awk'{$1=”“}1'
的变体,或者您只需要
cut-b15-
我非常喜欢这个解决方案,因为它的代码少得多,并且在我的脚本中可以很好地作为一个线性行程序使用。唯一的缺点是它缩短了时间:将行缩短到
18
,而不是说
0:02:18
。对于我的解决方案,这很好,因为我没有对时间值做任何特定的操作:)将
^.*
更改为
[^::]*
。这非常有效!我喜欢它是一段简洁的代码。最终,由于包含了
mapfile
命令,我在脚本中使用了这个解决方案。它工作得很好,所以谢谢你!!对于堆栈溢出,不鼓励使用仅代码的答案,因为它们没有解释堆栈溢出是如何解决问题的。请编辑您的答案,以解释此代码的作用以及它如何回答问题,以便对OP以及具有类似问题的其他用户有用。