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