• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fsckzy
V2EX  ›  程序员

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

  •  
  •   fsckzy · Jul 18, 2016 · 6514 views
    This topic created in 3760 days ago, the information mentioned may be changed or developed.
    求给点思路,
    文件是这样的,大概有 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 replies  •  2016-07-20 01:27:53 +08:00
    petelin
    petelin
    Jul 18, 2016 via Android
    1
    就是从空格分开吧,搜一下 awk
    fsckzy
    fsckzy
    OP
    Jul 18, 2016
    2
    @petelin 不是空格分开,是要 0-255 的生成
    billgreen1
    billgreen1
    Jul 18, 2016
    3
    2 个 1.0.16.2 是什么鬼?
    xmgit
    xmgit
    Jul 18, 2016
    4
    排序?
    awk 配合 sort
    changshu
    changshu
    Jul 18, 2016❤️1
    5
    两个 IP 之间的区间迭代 shell 下面有 prips 命令, python 下有 netaddr, 处理起来都很方便, 不过都需要装一下
    Owenjia
    Owenjia
    Jul 18, 2016
    6
    cat <filename> | awk '{print $1"\n"$2}' | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
    这样可以不?
    Owenjia
    Owenjia
    Jul 18, 2016
    7
    呃,不对,我好像理解错了……
    RIcter
    RIcter
    Jul 18, 2016 via iPhone
    8
    shell 可以的(
    fsckzy
    fsckzy
    OP
    Jul 18, 2016
    9
    楼上的都理解错了。
    fsckzy
    fsckzy
    OP
    Jul 18, 2016
    10
    @RIcter 能给点思路吗
    Owenjia
    Owenjia
    Jul 18, 2016
    11
    @fsckzy
    你想要的是不是这样的?
    echo 1.0.{16..31}.{0..255}
    changshu
    changshu
    Jul 18, 2016
    12
    parallel --colsep ' ' prips < ip.lst
    vimmer
    vimmer
    Jul 18, 2016
    13
    把这个理解为 256 进制的四维数, 就很简单了.
    fsckzy
    fsckzy
    OP
    Jul 18, 2016
    14
    @Owenjia 对,基本是这样,但是我里面的数字不是统一的,有 5000 多条,
    lightening
    lightening
    Jul 18, 2016
    15
    每一行从起始地址到终结地址展开吧?我觉得 Shell 可以,但不知道怎么写。没有特殊需求的话我会用 Python 写省事,但如果你的运行环境只有 shell 的话,肯定也是能用 shell 实现的。
    dibage
    dibage
    Jul 18, 2016
    16
    简单理解就是解析出两个 IP 段之间的 IP 地址列表,是吧?

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

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





    我的 shell 功底比较差,但是总体步骤可以参考。还可以优化但是懒得弄了。
    当然还有很多其它办法,楼上说了好几个比如 awk 也可以实现,但是还是那句话,看你想不想这样了因为我觉得 Python 简单。
    Owenjia
    Owenjia
    Jul 19, 2016 via Android
    24
    @msg7086
    awk 其实就是一种脚本语言吧…
    4everLoveU
    4everLoveU
    Jul 19, 2016
    25
    可以实现,思路:
    先 sort | uniq 排序去重
    然后 awk 用" . "切除前三个字符,后面的补一个 for 循环 0~255 ,最后作拼接即可...
    araraloren
    araraloren
    Jul 19, 2016
    26
    ~~ 对于脚本能解决的问题不存在实现不能实现的问题,只是方便不方便的问题
    ```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
    sualwu
    Jul 19, 2016
    27
    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
    wizardoz
    Jul 19, 2016
    28
    你是在问 bash 有没有循环功能?我告诉你,有!
    sunmsn
    sunmsn
    Jul 19, 2016
    29
    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
    Azus
    Jul 19, 2016
    30
    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
    itisthecon
    Jul 19, 2016
    31
    用 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
    Balthild
    Jul 20, 2016
    32
    跑个题, 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
    Balthild
    Jul 20, 2016
    33
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1309 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 67ms · UTC 21:39 · PVG 05:39 · LAX 13:39 · JFK 16:39
    ♥ Do have faith in what you're doing.