【问题标题】:Extract all ip addresses with sed and awk from a string使用 sed 和 awk 从字符串中提取所有 IP 地址
【发布时间】:2018-02-04 20:41:08
【问题描述】:

用grep从一个字符串中提取所有ip地址很简单。

string="221.11.165.237xxxx221.11.165.233\n
219.158.9.97ttttt219.158.19.137"
echo $string |grep -oP "(\d+\.){3}\d+"
221.11.165.237
221.11.165.233
219.158.9.97
219.158.19.137

正则表达式模式很简单(\d+\.){3}\d+
用 sed 和 awk 做同样的工作。
对于 sed:

echo $string | sed 's/^\(\(\d\+\.\)\{3\}\d\+\)$/\1/g'
221.11.165.237xxxx221.11.165.233\n 219.158.9.97ttttt219.158.19.137

对于 awk:

echo $string |gawk 'match($0,/(\d+\.){3}\d+/,k){print k}'
echo $string |awk '/(\d+\.){3}\d+/{print}'

如何解决 sed 和 gawk(awk) 的问题?
期望输出与 grep 相同。

221.11.165.237
221.11.165.233
219.158.9.97
219.158.19.137

【问题讨论】:

标签: bash awk sed


【解决方案1】:

很少有工具会识别\d 的含义为digits。只需改用[0-9][[:digit:]]

$ echo "$string" | awk -v RS='([0-9]+\\.){3}[0-9]+' 'RT{print RT}'
221.11.165.237
221.11.165.233
219.158.9.97
219.158.19.137

以上使用 GNU awk 进行多字符 RS 和 RT。使用任何 awk:

$ echo "$string" | awk '{while ( match($0,/([0-9]+\.){3}[0-9]+/) ) { print substr($0,RSTART,RLENGTH); $0=substr($0,RSTART+RLENGTH) } }'
221.11.165.237
221.11.165.233
219.158.9.97
219.158.19.137

【讨论】:

  • 和 sed 的正则表达式?
  • 这根本不是 sed 的工作。 sed 用于在单个行上进行简单替换,仅此而已。当您尝试使用 sed 做更多的事情时,您会陷入混乱的单字符符文和不可移植的构造。如果您正在做的不仅仅是s/old/new/,请使用 awk。并不是说你不能强制某些特定版本的 sed 做你想做的事,但结果涉及语言结构,在 1980 年代中期,当 awk 被发明时,这种结构实际上已经过时了。
  • 使用 mawk 或 original-awk 没有输出?
  • man mawk : AWK 使用扩展的正则表达式,就像 egrep(1) 一样。正则表达式元字符,即正则表达式中具有特殊含义的元字符是 ^ $ 。 [ ] | ( ) * + ?所以我们必须用 + 替换 {3}
  • @ctac_ egrep 多年来一直被grep -E 弃用。 Original-awk 也被称为旧的、损坏的 awk,任何人都不得将其用于任何目的,因此在任何关于 awk 中的工作/不工作的讨论中,甚至不要考虑这一点,因为它几乎没有任何作用。 mawk 有多个版本,其中一些非常旧,是 POSIX 之前的版本,并且功能有限,因为它专注于执行速度而不是功能。 {3} 之类的区间表达式是 ERE 的一部分(请参阅 pubs.opengroup.org/onlinepubs/9699919799),所有当前版本的所有 awk 都支持,包括 mawk。
【解决方案2】:

这可能对你有用(GNU sed):

sed '/\n/!s/[0-9.]\+/\n&\n/;/^\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\n/P;D' file

在仅由数字和句点组成的字符串的两侧插入换行符。如果一行只包含一个 IP 地址,则打印它。

使用-r 选项的更直观的再现:

sed -r '/\n/!s/[0-9.]+/\n&\n/;/^([0-9]{1,3}\.){3}[0-9]{1,3}\n/P;D' <<<"$string"

【讨论】:

    【解决方案3】:

    由于您没有具体说明 IP 地址之间的内容,因此我同意 IP 中只有数字和句点的事实:

    echo "$string" | sed -r 's/[^0-9.]+/\n/'
    
    echo "$string" | awk '1' RS="[^0-9.]+"
    

    【讨论】:

    • 你能详细解释一下awk '1' RS="[^0-9.]+"吗?
    • 这只适用于 GNU awk 并且会发现许多错误匹配,而不仅仅是 IP 地址。
    • 本质上 awk 和 sed 是相同的,因为它们用新行替换任何连续的非数字或句点。 1 只是打印出新格式。 Ed 是正确的,但根据我的假设,它仅适用于特殊情况
    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多