在vim中排序IP地址

7
我刚刚发现了vim中的命令:sort n(我怎么不知道?!),这个命令几乎完全符合我的需求。
但我想要排序的是一个长列表的IP地址(它是一个“允许主机”文件,需要被包含到我们的apache配置文件中),所以希望:sort n可以识别出123.45.6.7应该排在123.45.16.7之前(例如)。
我是否可以不那么纠结,因为我可能无法完成这个任务,除非使用稍微复杂的sedawk命令等?
清楚地说,这些行看起来都差不多:
Allow from 1.2.3.4
Allow from 5.6.7.8
Allow from 9.10.11.12

etc

4个回答

17

Vim的排序在实践中似乎是稳定的(但不能保证)。因此,你可以尝试:

:%sort n /.*\./
:%sort n /\.\d\+\./
:%sort n /\./
:%sort n

该方法将按最后一个点号后面的数字排序(* 为贪婪匹配),然后按照紧随着点号和数字的第一个点号后面的数字排序,接着按照第一个点号后面的数字排序,最后按照第一个数字排序。


几乎完美(唯一的原因是我没有提到我的某些行是网络掩码)。谢谢你;这让我足够远,可以自己解决网络掩码问题。 - Owen Blacker
7
使用管道可以在一次操作中执行所有内容::%sort n /.*\./ | %sort n /\.\d\+\./ | %sort n /\./ | %sort n - azzid

3

一个简单的方法来实现正确的排序顺序,而不依赖于:sort命令实现的排序算法的稳定性,就是在IP地址中的数字前面加上零,以便它们的所有组件都由三个数字组成。

  1. Prepend zeros to the single-digit and two-digit numbers:

    :%s/\<\d\d\?\>/0&/g|%&&
    
  2. Sort the lines comparing IP addresses as text:

    :sort r/\(\d\{3}\)\%(\.\d\{3}\)\{3}/
    
  3. Strip redundant leading zeros:

    :%s/\<00\?\ze\d//g
    
要一次运行三个步骤,可以使用以下单行命令:
:%s/\<\d\d\?\>/0&/g|%&&|sor r/\(\d\{3}\)\%(\.\d\{3}\)\{3}/|%s/\<00\?\ze\d//g

0

我不是vim用户,因此无法提供使用内置命令直接完成此操作的方法,但可以通过运行命令将文本部分替换为其输出。因此,可以使用以下简单脚本:

#!/usr/bin/python

import sys

input_lines = sys.stdin.readlines()
sorted_lines = sorted(input_lines,
                      key=lambda line: map(int, line.split()[-1].split('.')))
for line in sorted_lines:
    sys.stdout.write(line)

请参考https://www.linux.com/learn/tutorials/442419-vim-tips-working-with-external-commands中的“通过外部过滤器过滤文本”一节,该节解释了如何在vim中使用此过滤器。
此脚本应该可以实现您想要的功能,并且适用于所有选定行末尾都是IPv4地址的区域。

太好了,谢谢。我试图避免运行脚本(主要是因为它是一个尚未上线的生产服务器,所以只有基本安装,没有安装python),但这看起来很棒;谢谢! - Owen Blacker

0

您可以使用:

:%!sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n

-t . 表示使用 . 作为分隔符。 然后按照第四列到第一列进行数字排序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接