2017-04-17 117 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也进入巴蜀字符串操作细节。

相关问题