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以及具有类似问题的其他用户有用。