2017-04-17 68 views
1

我有一個格式包含數據這樣加快這一bash腳本

<Tag1>content 
<Tag2>optional tag content 
<Tag3>content 

<Tag1>other content 
<Tag3>other content 

凡標記每一塊代表來填充對象所需的數據文件。一些標籤也是可選的。

目前我處理的數據文件與此代碼

#!/bin/bash 
tag1="" 
tag2="" 
tag3="" 

while read line; do 

if [[ $line == '<Tag1>'* ]] 
    then 
    tag1=`echo $line | cut -c 6- | tr -d '\r'` 
elif [[ $line == '<Tag2>'* ]] 
    then 
    tag2=`echo $line | cut -c 6- | tr -d '\r'` 
elif [[ $line == '<Tag3>'* ]] 
    then 
    tag3=`echo $line | cut -c 6- | tr -d '\r'` 
    #write new object to output file and reset tag variables 
fi 

done <file.dat 

其中切標籤後得到的數據和TR刪除下列數據的任何新線。

此代碼非常慢,但特別是當您有數百個文件要處理數千行時。

會有更快的方式來做到這一點,並處理可選標籤(當不是隻是通過「」)與awk的東西?

編輯:

進出口使用它,所以我使用輸出來創建INSERT語句填充SQL表:

echo "INSERT INTO MyTable VALUES('$tag1','$tag2','$tag3');" >> output.sql 

第二編輯

鑑於

<Tag1>Some sample text including don't 
<Tag2>http://google.com 
<Tag3>$100 
輸入

理想的輸出是INSERT INTO MyTable Values(「一些示例文本包括不要」 ,「http://google.com」,「$ 100」);

很顯然,如果我打算用單引號傳遞值而不是引號,那麼我不得不在雙引號中加上「不要」這樣的撇號,這樣它就不會提早退出輸入。

+1

是的,在awk中重寫它會使其至少快一個數量級,請參閱[爲什麼使用shell循環處理文本被認爲是不好的練習](https:/ /unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice)。 [編輯]你的問題顯示給定的輸入預期的輸出,所以我們可以幫助你。 –

+0

@Ed現在編輯包含輸出 – najd1103

+0

@EdMorton對不起,我最近的編輯應該有希望回答你的問題 – najd1103

回答

3

這不是從你的問題清楚,因爲你還沒有表現出預期的輸出,但是這可能是你在找什麼:

$ cat tst.awk 
BEGIN { 
    RS = "" 
    FS = "\n" 
    fmt = "INSERT INTO MyTable VALUES(\047%s\047, \047%s\047, \047%s\047);\n" 
} 
{ 
    delete v 
    for (i=1;i<=NF;i++) { 
     tag = val = $i 
     gsub(/^<|>.*/,"",tag) 
     sub(/^[^>]+>/,"",val) 
     v[tag] = val 
    } 
    printf fmt, v["Tag1"], v["Tag2"], v["Tag3"] 
} 

這裏的類型的輸入文件,你應該問我們測試用,因爲它包含了一些傳統問題的字符和字符串:

$ cat file 
<Tag1>with 'single\' quotes 
<Tag2>http://foo.com 
<Tag3>trailing backslash\ 

<Tag1>With <some> "double\" quotes 
<Tag3>with \1 backrefs & here 

和這裏的輸出上面的腳本會產生因爲輸入:

$ awk -f tst.awk file 
INSERT INTO MyTable VALUES('with 'single\' quotes', 'http://foo.com', 'trailing backslash\'); 
INSERT INTO MyTable VALUES('With <some> "double\" quotes', '', 'with \1 backrefs & here'); 

如果有任何不是你想要的,然後編輯你的問題,以顯示輸入(或類似),加上你想要的輸出。

3

awk解決方案可能會更快,但這種猛砸解決方案應該是比你原來的代碼更快:

#!/bin/bash 
regex="^<Tag([1-3])>(.*)$" 
while IFS= read -r line 
do 
if 
    [[ $line =~ $regex ]] 
then 
    case ${BASH_REMATCH[1]} in 
    1) tag1=${BASH_REMATCH[2]} ;; 
    2) tag2=${BASH_REMATCH[2]} ;; 
    3) echo "INSERT INTO MyTable VALUES('$tag1','$tag2','${BASH_REMATCH[2]}');" >> output.sql 
     tag1= ; tag2= ;; 
    esac 
fi 
done <file.dat 

請注意,所有線路都與同一正則表達式匹配,則1/2/3由案件陳述處理。顯然,上述內容對於標籤或大小寫內部的空格非常敏感,因此,如果您需要容許變化,請考慮實際數據並對正則表達式進行必要的調整。