2016-04-26 103 views
0

上下文:我正在編寫一個shell腳本來幫助管理以文本文件以人類可讀方式存儲並使用普通文本編輯器進行編輯的簡單數據庫。 (每個條目是一個文本文件,其名稱是一個ID號,並且所有文件都存儲在一個目錄中。)POSIX正則表達式:僅在逗號分隔的項目內匹配

我目前的問題是搜索。有一些頭文件,它們基本上是文件頂部的數據字段。例如,我們來看一下標記字段,該字段從Tags:\t(其中\t是一個字面製表符)開始,然後有一個逗號分隔標記列表。我希望能夠將用戶提供的正則表達式插入到對grep的更大調用中,並且只有在每個逗號分隔項內,用戶的正則表達式匹配

下面是從我的文檔有點描述,我想發生什麼:


hregexes是僅在逗號分隔的項目匹配ERES。例如,對於首標Tags: foo, bar baz

REGEX  :: MATCHES? 
foo  :: yes 
bar  :: yes 
baz  :: yes 
az  :: yes 
.*baz  :: yes 
ba.*az :: yes 
o, ba  :: no 
foo.*baz :: no 

這將理想地純粹工作與POSIX擴展正則表達式,用於與系統的其餘部分的一致性;我有一個使用Python進行搜索的簡化版本,但決定我應該重寫那部分,以便系統不會搜索POSIX正則表達式和一些Python。

我確實試圖想出一個模式,但是我用regexps來做一些複雜的事情還不夠好。在以下嘗試中,$2是我們正在查找的標題,並且$3是在該標題中匹配的模式。

grep -El "$2: (|.*,|.*,)[^,]*$3[^,]*(,|\b)" *.dre 

這不會錯過它應該抓住任何結果,但它的問題在於o, bafoo.*baz都匹配時,他們不應該;在這一點上,我不妨只搜索$2: .*$3

如果這對於單個ERE來說是不可能的,那麼在Bash中是否有另一種好方法呢?我的數據庫已經有超過一千個文件,並且可以輕鬆增長到很多次,所以我不希望循環遍歷每個文件,然後遍歷逗號分隔列表中的每個項目,並且每次都會產生shell開銷。

回答

1

以下解決方案基於佩裏更換分離器的想法,並非萬無一失,但保留了理想的運行時間,同時使其非常難以擰緊。

首先,我們選擇一個分隔符來替換逗號;我選擇了@@@@@,推理這不會發生在任何正確形成的標籤。 (這種標籤通常是純字母。)

然後,我們修改用戶的正則表達式與[^@]更換.,從而沒有表達會越過邊界@@@@@除非明確組成的。我可能會錯過其他一些比賽,比如說[[:punct:]];我並不十分擔心這些,但如果有人對其他特殊字符的想法可能有問題,我想聽聽他們的消息。

最後,我們創建一個包含所有Tags線流,編輯,使其包含只是文件名和新@ -delimited標籤,用戶的模式匹配應用到該流,然後刪除一切,但在文件名比賽流。

最終代碼:

header="$2" 
pattern=$(echo "$3" | sed -e 's/\./[^@]/') 
grep -m 1 "$header: " *.dre | sed -e "s/$header:  //" | \ 
    sed -e 's/, /@@@@@/g' | grep -E "$pattern" | \ 
    sed -e 's/\([0-9]\{5\}\.dre\):.*/\1/' 

[0-9]\{5\}\.dre是匹配所有合法文件名的表達式。)

輸出示例:

00775.dre 
00787.dre 
00788.dre 
00883.dre 
00889.dre 

(顯然,匹配可以被保存到可變的進一步處理;這就是我在這裏做的。)

+0

我沒有嘗試,但它看起來像你在正確的軌道上。你也碰到了在純shell中能夠實現的限制,所以請記住,來自用戶的下一個功能請求可能會促使你用更低級的語言編寫一些幫助程序:) – Perry

1

訣竅是將逗號更改爲更好的作爲grep中的分隔符,即換行符。

head -1 $DATA_FILE | sed -E 's/,/\'$'\n/g' | grep -qE "$SEARCH" 

if [ $? == 0 ] 
then 
    echo "Pattern found: $DATA_FILE" 
else 
    echo "Pattern not found: $DATA_FILE" 
fi 

$DATA_FILE是包含標籤的文件。 $SEARCH是正在尋找的正則表達式。

if聲明顯然會被適合您的應用程序的邏輯替代。

head命令從文件中提取第一行(「Tag:」行)。 sed命令用換行符替換該行上的所有逗號(在這一點上刪除「Tag:」可能是明智的做法,以避免誤報)。 grep然後只需搜索輸入正則表達式的每一行結果集並返回一個狀態,指示是否找到它。

搜索每個數據文件的最小數量。

+0

這個作品(除了'標籤'不一定是第一行,所以我使用'grep -hm 1'標籤:''),但它需要循環Bash中的目錄中的每個文件,這已經減慢了搜索的速度因子爲60,幾乎從用戶的角度瞬間變爲幾秒。 –

+0

我想我已經找到了一個可行的解決方案,我已經發布了一個答案;我很想聽聽你的想法。 –

相關問題