2013-08-26 120 views
1

我需要编写一个脚本来对长字符串执行一些魔术并更改输出。除了一部分外,我可以轻松完成大部分脚本。BASH字符串解析

如果我有了

data = “CRITICAL - mempool lsmpi_io usage is 99.99%, mempool Processor usage is 34.38% | 'Processor_usage'=34.38%;80;90 'lsmpi_io_usage'=99.99%;80;90” 

我需要总是之后的信息bash脚本“‘Processor_usage’=”

命令做我需要做的,使

$p=34.38 
$w=80 
$c=90 

请记住,百分比可能只是一个数字。

+1

这真的是一个bash脚本或整条线是数据本身吗?在带有赋值的Bash中使用'='左右的空格会导致语法错误。 – konsolebox

+1

只是好奇,为什么你需要使用bash解析一个nagios插件的输出? –

+0

Adrian,因为插件的作者没有反应,我不能编辑它,因为它是成千上万行的代码,并不知道从哪里开始。这个回复是针对非常特定的路由器内存使用情况。我们只有4个,而lsmpi_io池总是100%的使用,所以这4个路由器的插件结果是没有用的。 – BanditBBS

回答

1

纯bash的解决方案:

data=${data##*\'Processor_usage\'=} 
data=${data%% *} 
IFS=';' read p w c <<< "$data" 


echo "p=${p%\%}" # or echo "p=${p:0:-1}" 
echo "w=$w" 
echo "c=$c" 

将输出这样的:

p=34.38 
w=80 
c=90 
+0

我想知道OP究竟是什么意思,“记住百分比可能只是一个数字”。这实际上可能会影响到人们如何决定是否必须排除最后一个字符。尽管如此,我认为使用数组并不是必需的。你可以只读'p w c <...'和'p = $ {p%'%'}'。 – konsolebox

+0

我还担心file.txt是否只有'* Processor_usage *'以外的其他数据。如果是这种情况,我们应该过滤它,只有纯粹使用bash才是不切实际的。 – konsolebox

+0

@konsolebox 是的,你说得对,当我看到你的评论时,我几乎完成了编辑。但我不同意''p = $ {p%'%'}''。子串看起来更简单,效果更好:) –

0

你可以使用例如sed。以下的例子来标记你所指出的字符串:

#!/bin/sh 

DATA="CRITICAL - mempool lsmpi_io usage is 99.99%, mempool Processor usage is 34.38% | 'Processor_usage'=34.38%;80;90 'lsmpi_io_usage'=99.99%;80;90" 

echo "$DATA" | sed "[email protected]*'Processor_usage'=\([0-9.]*\)%;\([0-9.]*\);\([0-9.]*\) .*@\1 \2 \[email protected]" | while read p w c; do 
    echo p=$p 
    echo w=$w 
    echo c=$c 
done 
+0

-1使用'echo $ DATA'(在向'echo'形成参数时字符串拆分并全局扩展内容,并因此修改数据通过时)。 'echo“$ DATA”'会更不准确,即使仍然不必要地低效。 –

+0

另外,没有任何理由使得这是一个由子进程继承的环境变量;如果你遗漏了'export'(并且按照惯例,将变量名变成小写),那么这会更有意义。 –

0

如果这段文字是在一个文件:

data = “CRITICAL - mempool lsmpi_io usage is 99.99%, mempool Processor usage is 34.38% | 'Processor_usage'=34.38%;80;90 'lsmpi_io_usage'=99.99%;80;90” 

此命令会得到你的要求:

IFS=';' read p w c < <(sed -n "/Processor_usage/{ s|.*'Processor_usage'=||; s| .*||; s|%||g; p; }" file) 
0

这应该工作:

read p w c < <(grep -oP "(?<='Processor_usage'=)[^\s]+" <<< $data | tr ';' ' ') 

echo -e "p=${p}\nw=${w}\nc=${c}" 
p=34.38% 
w=80 
c=90 
3

bash有内置的正则表达式的支持;绝对没有理由使用sed等外部工具。

data="CRITICAL - mempool lsmpi_io usage is 99.99%, mempool Processor usage is 34.38% | 'Processor_usage'=34.38%;80;90 'lsmpi_io_usage'=99.99%;80;90" 
data_re="'Processor_usage'=([0-9.]+)%?;([0-9.]+)%?;([0-9.]+)%?" 
if [[ $data =~ $data_re ]]; then 
    p=${BASH_REMATCH[1]} 
    w=${BASH_REMATCH[2]} 
    c=${BASH_REMATCH[3]} 
fi 
+0

BASH_REMATCH的有趣用法。如果Bash版本是4.0或更新版本,应该很有用。尽管按照OP的要求,您仍然应该删除'%'符号。如果数据是多行文件的一部分,sed实际上是用来使用的。而且,对于兼容性参数替换和'read'将是更好的选择。 – konsolebox

+0

@konsolebox更新为修剪'%'字符。 'BASH_REMATCH'在bash 3.x中可用,并且这种特定的使用模式一直支持到3.0,所以这是_not_ 4.x特定的。 –

+0

只有'=〜'的实现因版本而异。至少4.0+或许变得更加稳定。做'[[A =〜(A)]]'会在早期版本中导致语法错误,而像'(A)'这样应该是文字字符串的引用模式被解释为regex。也许将模式存储在一个变量上会解决它,但是由于这个要求,我发现扩展模式更好,并且除非是4.0+,否则从来没有真正依赖于它。我其实认为BASH_REMATCH没有工作,所以我说4.0。 – konsolebox