首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fsckzy
V2EX  ›  程序员

shell 能实现这样的功能吗?还是要 python?

  •  
  •   fsckzy · 2016-07-18 20:53:48 +08:00 · 3650 次点击
    这是一个创建于 1354 天前的主题,其中的信息可能已经有所发展或是发生改变。
    求给点思路,
    文件是这样的,大概有 5000 多条
    1.0.16.0 1.0.31.255
    1.0.64.0 1.0.127.255
    1.1.64.0 1.1.127.255
    1.5.0.0 1.5.255.255
    1.21.0.0 1.21.255.255


    要用 shell 把它生成这样的
    比如说 1.0.16.0 1.0.31.255 ,就要如下的效果
    1.0.16.0
    1.0.16.1
    1.0.16.2
    1.0.16.2

    。。。
    1.0.16.255
    1.0.17.0
    1.0.17.1
    1.0.17.255
    1.0.18.0
    1.0.18.255
    ...
    1.0.31.0
    1.0.31.255
    33 条回复    2016-07-20 01:27:53 +08:00
    petelin
        1
    petelin   2016-07-18 21:04:47 +08:00 via Android
    就是从空格分开吧,搜一下 awk
    fsckzy
        2
    fsckzy   2016-07-18 21:07:36 +08:00
    @petelin 不是空格分开,是要 0-255 的生成
    billgreen1
        3
    billgreen1   2016-07-18 21:10:17 +08:00
    2 个 1.0.16.2 是什么鬼?
    Bardon
        4
    Bardon   2016-07-18 21:11:14 +08:00
    排序?
    awk 配合 sort
    changshu
        5
    changshu   2016-07-18 21:12:46 +08:00   ❤️ 1
    两个 IP 之间的区间迭代 shell 下面有 prips 命令, python 下有 netaddr, 处理起来都很方便, 不过都需要装一下
    Owenjia
        6
    Owenjia   2016-07-18 21:34:25 +08:00
    cat <filename> | awk '{print $1"\n"$2}' | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
    这样可以不?
    Owenjia
        7
    Owenjia   2016-07-18 21:35:41 +08:00
    呃,不对,我好像理解错了……
    RIcter
        8
    RIcter   2016-07-18 21:35:44 +08:00 via iPhone
    shell 可以的(
    fsckzy
        9
    fsckzy   2016-07-18 21:48:07 +08:00
    楼上的都理解错了。
    fsckzy
        10
    fsckzy   2016-07-18 21:48:17 +08:00
    @RIcter 能给点思路吗
    Owenjia
        11
    Owenjia   2016-07-18 21:49:29 +08:00
    @fsckzy
    你想要的是不是这样的?
    echo 1.0.{16..31}.{0..255}
    changshu
        12
    changshu   2016-07-18 21:50:31 +08:00
    parallel --colsep ' ' prips < ip.lst
    vimmer
        13
    vimmer   2016-07-18 21:54:02 +08:00
    把这个理解为 256 进制的四维数, 就很简单了.
    fsckzy
        14
    fsckzy   2016-07-18 22:05:05 +08:00
    @Owenjia 对,基本是这样,但是我里面的数字不是统一的,有 5000 多条,
    lightening
        15
    lightening   2016-07-18 22:12:30 +08:00
    每一行从起始地址到终结地址展开吧?我觉得 Shell 可以,但不知道怎么写。没有特殊需求的话我会用 Python 写省事,但如果你的运行环境只有 shell 的话,肯定也是能用 shell 实现的。
    dibage
        16
    dibage   2016-07-18 22:14:20 +08:00
    简单理解就是解析出两个 IP 段之间的 IP 地址列表,是吧?

    我推荐用 Python 去实现,思路就是先把 IP 地址转换为整数,然后通过循环两个 IP 段数值计算出这个 IP 段内的 IP 列表。

    参考链接: http://stackoverflow.com/questions/5619685/conversion-from-ip-string-to-integer-and-backward-in-python
    likuku
        17
    likuku   2016-07-18 22:15:05 +08:00
    或者,先转化成 ipv4 的本源: 32 位的 2 进制数字,再进行你的需求运算,结果转成给人类阅读的 点分 4 个 10 进制数
    heqiang1068
        18
    heqiang1068   2016-07-18 22:32:00 +08:00   ❤️ 2
    必须是万能的 awk:
    awk '{split($1,a,".");split($2,b,".");for(i=a[3];i<=b[3];i++){for(j=a[4];j<=b[4];j++){print a[1]"."a[2]"."i"."j}}}' file.txt
    msg7086
        19
    msg7086   2016-07-18 23:57:05 +08:00
    自然是可以用 shell 来写,不过通常用高级语言写起来更舒服些,比较容易维护。
    至少不像楼上这么长的 awk 那么难懂……
    RIcter
        20
    RIcter   2016-07-19 00:04:41 +08:00 via iPhone
    @fsckzy 想了一下感觉很麻烦…
    smilejustforfan
        21
    smilejustforfan   2016-07-19 01:12:04 +08:00
    man ipcalc
    caola
        22
    caola   2016-07-19 01:27:15 +08:00
    如果系统自带的东西可以实现,建议尽量不要使用第三方语言或工具,
    当然如果效率和占用的资源适合的话,可以考虑自己认为适合的语言来实现
    DravenJohnson
        23
    DravenJohnson   2016-07-19 05:20:48 +08:00
    实现肯定可以,只是看你想不想这样做,个人感觉还不如写一个 Python 快且容易:





    我的 shell 功底比较差,但是总体步骤可以参考。还可以优化但是懒得弄了。
    当然还有很多其它办法,楼上说了好几个比如 awk 也可以实现,但是还是那句话,看你想不想这样了因为我觉得 Python 简单。
    Owenjia
        24
    Owenjia   2016-07-19 09:30:23 +08:00 via Android
    @msg7086
    awk 其实就是一种脚本语言吧…
    4everLoveU
        25
    4everLoveU   2016-07-19 09:44:49 +08:00
    可以实现,思路:
    先 sort | uniq 排序去重
    然后 awk 用" . "切除前三个字符,后面的补一个 for 循环 0~255 ,最后作拼接即可...
    araraloren
        26
    araraloren   2016-07-19 10:04:44 +08:00
    ~~ 对于脚本能解决的问题不存在实现不能实现的问题,只是方便不方便的问题
    ```perl6
    #!/usr/bin/env perl6

    sub ip2Int(@ip) {
    my Int $ipint = 0;

    for ^4 {
    $ipint +<= 8; $ipint +|= @ip[$_];
    }
    $ipint;
    }

    sub int2Ip($ipint) {
    my @ip;

    @ip.push: ($ipint +> (8 * .Int)) +& 0xff for ^4;
    @ip.reverse;
    }

    say int2Ip($_) for ip2Int([1, 0, 16, 0]) ... ip2Int([1, 0, 31, 255]);
    ```
    下面是测试 测试,如果你是想要的这种效果的话。。
    [TEST LINK]( https://ideone.com/KOG2Gp)
    sualwu
        27
    sualwu   2016-07-19 10:52:13 +08:00
    debian8:~$ cat iplists
    1.1.1.250 1.1.2.10
    1.1.2.252 1.1.3.2

    debian8:~$ for iplist in `cat iplists | sed -r 's/\s+/##/g'`; do intip1=`echo $iplist | awk -F'##' '{print $1}' | awk -F. '{print($1*2^24+$2*2^16+$3*2^8+$4)}'`; intip2=`echo $iplist | awk -F'##' '{print $2}' | awk -F. '{print($1*2^24+$2*2^16+$3*2^8+$4)}'`; for ((ip=$intip1;ip<=$intip2;ip++)); do ((i1=$ip>>24,i2=$ip>>16&0x00ff,i3=$ip>>8&0x0000ff,i4=$ip&0x000000ff)); echo $i1.$i2.$i3.$i4; done; done
    1.1.1.250
    1.1.1.251
    1.1.1.252
    1.1.1.253
    1.1.1.254
    1.1.1.255
    1.1.2.0
    1.1.2.1
    1.1.2.2
    1.1.2.3
    1.1.2.4
    1.1.2.5
    1.1.2.6
    1.1.2.7
    1.1.2.8
    1.1.2.9
    1.1.2.10
    1.1.2.252
    1.1.2.253
    1.1.2.254
    1.1.2.255
    1.1.3.0
    1.1.3.1
    1.1.3.2
    wizardoz
        28
    wizardoz   2016-07-19 11:25:29 +08:00
    你是在问 bash 有没有循环功能?我告诉你,有!
    sunmsn
        29
    sunmsn   2016-07-19 16:20:48 +08:00
    import netaddr

    def ip2int(addr):
    return int(netaddr.IPAddress(addr))

    def int2ip(addr):
    return str(netaddr.IPAddress(addr))

    with open('data.txt','r') as f:
    for line in f:
    ip_1,ip_2 = line.strip().split()
    for i in range(ip2int(ip_1),ip2int(ip_2)+1):
    print int2ip(i)
    print '-'*80
    Azus
        30
    Azus   2016-07-19 18:30:50 +08:00
    shell scripts 不就是用来利用和关联各种程序的么, 避免造轮子才是应该的
    如果是在 debian 系, 12 楼 @changshu 的答案最好
    redhat 系有些不幸,没有 prips, 这个轮子似乎还是可以造一下

    @DravenJohnson 23 楼的实现不对, 1.0.16.10 到 1.0.17.0 之间的 ip 缺失

    纯 Bash, 没觉得比其它的复杂, 还不依赖其它软件

    usage: ./prips.sh iplists_file

    ----
    #!/usr/bin/env bash

    ip2int() {
    local i
    local int

    for i in {0..3}; do
    ((int <<= 8))
    ((int += $1[i]))
    done
    echo $int
    }

    int2ip() {
    local i

    int=$1

    for i in {0..3}; do
    ((ip[i] = int & 255))
    ((int >>= 8))
    done
    echo ${ip[3]}.${ip[2]}.${ip[1]}.${ip[0]}
    }

    while read -ra ipl; do
    s=(${ipl[0]//./ })
    e=(${ipl[1]//./ })

    for ((i = $(ip2int s); i <= $(ip2int e); i++)) {
    int2ip $i
    }
    done < $1
    ----
    itisthecon
        31
    itisthecon   2016-07-19 18:39:38 +08:00
    用 perl , 应该是最简洁了吧:

    #!/usr/bin/perl
    use 5.10.1;
    use Socket;
    open ( FH,'iplist' );
    while ( <FH> ){
    my @a = split;
    $s = unpack("N", inet_aton ( "$a[0]" ));
    $e = unpack("N", inet_aton ( "$a[1]" ));
    for ( $i=$s;$i<=$e;$i++ ){
    say inet_ntoa(pack("N", $i));
    }
    }
    Balthild
        32
    Balthild   2016-07-20 01:21:13 +08:00
    跑个题, php

    $arr = explode(" ", $input);
    $long1 = ip2long($arr[0]);
    $long2 = ip2long($arr[1]);
    for ($i = $long1; $i <= $long2; $i++) {
    $ips[] = long2ip($i);
    }
    print_r($ips);
    Balthild
        33
    Balthild   2016-07-20 01:27:53 +08:00
    好像漏了些什么东西……

    补齐:
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3122 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 13:55 · PVG 21:55 · LAX 06:55 · JFK 09:55
    ♥ Do have faith in what you're doing.