Grep
模式匹配排除重複字元
以下是否有一個正則表達式匹配字元集中的字元但只匹配一次?換句話說,一旦找到一個角色,就將其從集合中移除。
如果 grep 不能做到這一點,是否有一個內置的實用程序可以做到這一點?
例子:
Characters to match only once: spine
輸入:
spine spines spin pine seep spins
輸出:
spine spin pine
編輯:
有很多方法可以實現這個輸出(下面的一個例子),但我正在尋找一種方法來做到這一點,而不必為我想要匹配的每個模式自定義命令。
grep '[spine]' input_file | grep -v 's.*s' | ... | grep -v 'e.*e'
使用數學意義上的正則表達式是可能的,但是正則表達式的大小相對於字母表的大小呈指數增長,因此不實用。
否定和反向引用有一個簡單的方法。
grep '[spine]' | grep -Ev '([spine]).*\1'
第一個
grep
選擇包含至少一個的行einps
;第二個grep
拒絕包含多個任何一個的行(例如,允許spinal tap
和spend
但不允許foobar
或see
)。
受你的表達的啟發,我可以用 egrep 想出一個更短的:
egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE
這相當於
sed /s.*s/d;/p.*p/d;/i.*i/d;/n.*n/d;/e.*e/d; FILE
這就是如何從輸入中自動生成 sed 命令:
#!/bin/bash word=$1 file=$2 expr=$(for c in $(echo $word | sed 's/./& /g'); do echo -n "/"$c".*"$c"/d;"; done); sed $expr $file
我用 grep 嘗試了類似的方法,但無法說服 shell 從變數中獲取 grep 模式,但是如果我將其呼應出來,並通過剪切和粘貼插入結果,則該命令有效:
expr="'("$(for c in $(echo $wort | sed 's/./& /g'); do echo -n $c".*"$c"|"; done) egrep -v ${expr/%|/)\'} FILE # doesn't work, filters nothing, whole file is printed # check: echo egrep -v $(echo $exp) FILE egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE # manually: egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE spine spin pine
也許我犯了一個錯誤,也許我在變數擴展方面犯了一個錯誤。