我对程序的输出有问题。我需要在 bash 中启动一个命令并获取其输出(一个字符串)并将其拆分以在某些位置添加新行。该字符串如下所示:
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
基本上它是一个xxx.yy.zz:值,但该值可能包含空格。这是我想要得到的输出
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
我有一个想法,搜索第一个点,然后从该位置向后查找空间以在那里放置新行,但我不确定如何在 Bash 中实现它。
答案1
纯bash解决方案,没有使用外部工具来处理字符串,只是参数扩展:
#! /bin/bash
str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'
IFS=: read -a fields <<< "$str"
for (( i=0 ; i < ${#fields[@]} ; i++ )) ; do
f=${fields[i]}
notfirst=$(( i>0 ))
last=$(( i+1 == ${#fields[@]} ))
(( notfirst )) && echo -n ${f% *}
start=('' $'\n' ' ')
colon=('' ': ')
echo -n "${start[notfirst + last]}${f##* }${colon[!last]}"
done
echo
说明:$notfirst
和$last
是布尔值。第一个字段不会打印最后一个空格之前的部分${f% *}
,因为没有这样的东西。$start
并$colon
保存分隔字段的各种字符串:第一项notfirst + last
为 0,因此没有任何内容前置,对于其余行,$notfirst
为 1,因此打印换行符,对于最后一行,加法给出 2,因此打印出一个空格。然后,打印最后一个空格之后的部分${f##* }
。除最后一行外,所有行都打印冒号。
答案2
使用 GNU sed,您可以匹配以 结尾的每个连续字符串(即没有空格):
,然后在除第一个字符串之外的所有字符串之前放置一个换行符:
sed 's/[^[:space:]]\+:/\n&/g2'
如果您的 sed 版本不支持gn
扩展,您可以使用普通g
修饰符
sed 's/[^[:space:]]\{1,\}:/\
&/g'
除了在第一个键之前打印一个额外的换行符之外,它的工作方式相同。您可以使用perl -pe 's/\S+:/\n$&/g'
相同的附带条件(可能有 GNU sed 的 perl 等效项,g2
但我不知道)。
答案3
一个perl
办法:
$ perl -pe 's{\S+:}{$seen++ ? "\n$&" : "$&"}ge' file
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
解释
\S+:
匹配字符串结尾为:
.- 对于所有匹配的字符串,我们在它们之前插入换行符(
("\n$&")
第一个除外)($seen++)
。
答案4
这是一种简单的方法,假设您不关心输入中的制表符和换行符(如果有)被转换为普通空格,则该方法应该有效。
这个想法很简单:在空格上分割输入,并打印每个标记,除了在:
前面添加以换行符结尾的标记(并在其他标记前面重新添加一个空格)。变量$count
和相关变量if
仅用于防止初始空行。如果没问题的话可以删除。 (该脚本假定输入位于intput
当前目录中调用的文件中。)
#! /bin/bash
count=0
for i in $(<input) ; do
fmt=
if [[ $i =~ :$ ]] ; then
if [[ $count -gt 0 ]] ; then
fmt="\n%s"
else
fmt="%s"
fi
((count++))
else
fmt=" %s"
fi
printf "$fmt" "$i"
done
echo
echo "Num items: $count"
我希望有人能想出一个更好的选择。
$ cat input
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
$ ./t.sh
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Num items: 6