2017-04-17 67 views
1

Bash + debian。爲什麼 d +或 d +在這裏不等於 d *?

匹配信息結尾處的端口號。

s="2017-04-17 08:16:14 INFO  connecting lh3.googleusercontent.com:443 from 111.111.111.111:26215" 
echo $s | sed 's/\(.*\):\(\d*\)/\2/' 
26215 

讓我們將它與sed中的\ d +或\ d +進行匹配。

echo $s | sed 's/\(.*\):\(\d\+\)/\2/' 
echo $s | sed 's/\(.*\):\(\d+\)/\2/' 

所有這些都獲得整個字符串作爲輸出。

2017-04-17 08:16:14 INFO connecting lh3.googleusercontent.com:443 from 111.111.111.111:26215 

它們都不能匹配端口號,爲什麼?

+2

sed沒有'\ d'字符類......第一個是因爲'\ d'與'd'相同而'd *'可以是空的......'\ 2'是空的。 ..'sed's/\(。* \):\(\ d * \)/ \ 2 /''就是直接刪除最後一行':'在這行......你可以用任何字母替換'd'。 ..'sd \ /(。* \):\(\ q * \)/ \ 2 /' – Sundeep

+1

Sundeep說 - '\ d'在'sed'中不起作用。改用'[[:digit:]]'。 –

+4

當我用'sed'開始時,我有[類似問題](https://unix.stackexchange.com/questions/279368/sed-regular-expression-behaving-differently-than-in-vim-and-perl).. 。隨着時間的推移,人們傾向於學習有太多正則表達式風格的教訓...... – Sundeep

回答

3

有一個簡單的sed模式的使用方法:

$ echo "$s" | sed -nE 's/.*:([^:])/\1/p' 
26215 

正如評論指出,經常sed沒有perl元字符。您需要使用POSIX字符類的[[:digit:]]

說明:

sed -nE 's/.*:([^:])/\1/p' 
    ^      only print if there is a match 
    ^      use ERE and you don't need to escape the parens 
     ^     capture up to the rightmost : 
      ^^   -E means you don't need to escape parens 
       ^   all characters except : 
         ^ print if there is a match 

或者,如果您想更具體一些,你只想要個數字:

$ echo "$s" | sed -nE 's/.*:([[:digit:]]+$)/\1/p' 
26215 

+,以確保有至少要有一個數字並且$只能匹配行末。

有一個不同的正則表達式的摘要HERE。與-E sed使用ERE與egrep相同。

0
s="2017-04-17 08:16:14 INFO  connecting lh3.googleusercontent.com:443 from 111.111.111.111:26215" 

1.grep

echo $s |grep -Po '\d+$' 

2.ack

echo $s |ack -o '\d+$' 

3.sed

echo $s |sed 's/.*\://' 

4.awk

echo $s |awk -F: '{print $NF}' 
+0

'echo $ s'有點小錯誤 - 例如,如果你的's'包含一個被空格包圍的'*',它會是替換爲當前目錄中的文件列表。改用'echo「$ s」'。 –

+0

(另外,'grep -P'是一個非標準的擴展 - 它在MacOS上沒有,例如沒有安裝有MacPorts或Homebrew的GNU grep;甚至可能不在沒有可選支持的情況下編譯GNU grep的準系統Linux系統上使用爲libpcre)。 –

0

自答案由OP從問題轉移到社區維基答案,每consensus on meta


沒有表達\ d靜置數在sed。

要使用AWK得到簡單地:

echo $s |awk -F: '{print $NF}' 
26215 
2

\d是PCRE擴展在BRE或ERE語法(13759標準UNIX工具)不存在。

在這種特殊情況下,有沒有必要使用沒有內置的bash任何工具用於此目的不惜一切:

s="2017-04-17 08:16:14 INFO  connecting lh3.googleusercontent.com:443 from 111.111.111.111:26215" 
echo "Port is ${s##*:}" 

這是一個parameter expansion;當處理少量數據時,這種內置功能比運行外部工具更有效率。

還有shell內置原生支持ERE,如下:

re=':([[:digit:]]+)$' 
[[ $s =~ $re ]] && echo "Port is ${BASH_REMATCH[1]}" 

BashFAQ #100也進入巴蜀字符串操作細節。

相關問題