V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
webjin
V2EX  ›  Linux

这个逻辑怎么用 bash 实现

  •  
  •   webjin · 2014-03-07 10:38:36 +08:00 · 5734 次点击
    这是一个创建于 3905 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我的需求是 有2个文件,求 1.txt和ip.txt不同的内容。
    ip.txt文件内容是
    192.168.0.1
    192.168.0.2
    ....
    ....
    192.168.0.255
    就是1-255的IP
    而1.txt 是随机的一些ip是我在交换机ARP表里面获取到的
    192.168.0.9
    192.168.0.11
    192.168.0.14
    192.168.0.126
    192.168.0.18
    等差不多有50个吧
    现在我要整理哪些IP没在用。就写了一个bash脚本来处理
    但是运行这个脚本没报错。但是ip.txt的内容变空了,按照我的逻辑思路,ip.txt已经是把1.txt的相同内容过滤掉了。
    #!/usr/bin/env bash
    for ip in $(cat 1.txt)
    do
    grep -v "$ip" ip.txt > ip.txt
    done
    38 条回复    1970-01-01 08:00:00 +08:00
    wwwjfy
        1
    wwwjfy  
       2014-03-07 10:48:22 +08:00
    grep ... ip.txt | sponge ip.txt
    jakwings
        2
    jakwings  
       2014-03-07 10:52:30 +08:00
    上面 wwwjfy 才是对的……不要胡乱猜测工具在输出内容前会不会为你缓存整个文本的内容,因为工具为了资源消耗的考虑可能不会如你所愿。
    webjin
        3
    webjin  
    OP
       2014-03-07 11:02:14 +08:00
    @jakwings 包错 ./ip.sh: line 4: sponge: command not found 是不是sponge是一个单独的工具,要安装的?
    jakwings
        4
    jakwings  
       2014-03-07 11:08:19 +08:00
    @webjin 明显是的。要省事的话直接弄一个临时文件更快。
    7rack
        5
    7rack  
       2014-03-07 11:10:36 +08:00   ❤️ 1
    你的代码乍一看没错,其实是你在同一管道中读写同一文件,这里是问题。所以你可以改为
    grep -v "$ip" ip.txt > iptmp.txt
    mv iptmp.txt ip.txt
    试试
    Mutoo
        6
    Mutoo  
       2014-03-07 11:40:16 +08:00
    sort 完 diff 不就行了?
    duzhe0
        7
    duzhe0  
       2014-03-07 11:46:38 +08:00
    sort 1.txt > using.txt
    sort ip.txt > all.txt
    comm -13 1.txt ip.txt > unused.txt
    duzhe0
        8
    duzhe0  
       2014-03-07 11:47:16 +08:00
    错了,最后一行应该是
    comm -13 using.txt all.txt > unused.txt
    kfll
        9
    kfll  
       2014-03-07 12:07:11 +08:00   ❤️ 1
    grep -E -v "($(echo -n $(< 1.txt) | tr '[[:blank:]]*' '|'))" ip.txt
    webjin
        10
    webjin  
    OP
       2014-03-07 12:22:12 +08:00
    @7rack 谢谢了,同一管道中读写同一文件 。是我这个问题困扰我很久,为什么想不通,他grep输出来的内容然后再重定向到他本身文件会清空,如果是>>他会添加但是> 他直接清空。
    webjin
        11
    webjin  
    OP
       2014-03-07 12:23:36 +08:00
    @duzhe0 comm 这个命令很少用。我去了解他下的功能。
    webjin
        12
    webjin  
    OP
       2014-03-07 12:25:41 +08:00
    @kfll 谢谢你的回答 ,你正则表达式用的很熟练。但是我不明白里面的含义。
    webjin
        13
    webjin  
    OP
       2014-03-07 12:27:55 +08:00
    @duzhe0 非得先排序然后再来comm吗?
    webjin
        14
    webjin  
    OP
       2014-03-07 12:30:40 +08:00
    @duzhe0 我实验了一下,但是我发行他最后重新输出了内容就不是排好序的,是打乱了顺序。
    winsweet
        15
    winsweet  
       2014-03-07 12:37:33 +08:00   ❤️ 2
    cat 1.txt ip.txt ip.txt | sort | uniq -u
    webjin
        16
    webjin  
    OP
       2014-03-07 12:44:44 +08:00
    其实这种方法也可以吧
    #!/usr/bin/env bash
    for ip in $(cat 1.txt)
    do
    grep -v "$ip" ip.txt | tee ip.txt
    done
    webjin
        17
    webjin  
    OP
       2014-03-07 12:54:25 +08:00
    我要纠正下我刚才实验了一下 grep -v "$ip" ip.txt | tee ip.txt
    这个方法不行,因为我对比了 1.txt和ip.txt文件 最后输出的结果不一样,他多处理很多IP 。结果不正确。
    webjin
        18
    webjin  
    OP
       2014-03-07 12:55:17 +08:00
    @winsweet 嗯 我怎么没想到 uniq呢? 这算是最简单的了。
    amyangfei
        19
    amyangfei  
       2014-03-07 12:58:57 +08:00
    http://stackoverflow.com/questions/4780203/deleting-lines-from-one-file-which-are-in-another-file
    这个链接有一些讨论还有一个简单的性能比较
    grep -v -x -f 1.txt ip.txt 用这种方法貌似会多一些结果,不清楚为什么
    webjin
        20
    webjin  
    OP
       2014-03-07 13:01:08 +08:00   ❤️ 1
    @7rack 我发现 他跟 grep -v "$ip" ip.txt | tee ip.txt 输出的结果不正确,会多删掉 1.txt里面没有的内容。
    webjin
        21
    webjin  
    OP
       2014-03-07 13:04:32 +08:00
    @kfll 这种方法输出的结果也是不正确。
    amyangfei
        22
    amyangfei  
       2014-03-07 13:05:24 +08:00
    @webjin
    cat ip.txt
    192.168.0.1
    192.168.0.10
    192.168.0.100
    比如:grep -v 192.168.0.10 ip.txt|tee ip.txt
    会把192.168.0.100也删除
    webjin
        23
    webjin  
    OP
       2014-03-07 13:07:50 +08:00
    @winsweet 大哥你多了个 ip.txt ,哎,我怎么没想到 先拼接文件,然后排序 然后去重复。
    rrfeng
        24
    rrfeng  
       2014-03-07 13:09:54 +08:00
    最简洁的答案应该是 :grep -vf 1.txt ip.txt

    > 如果目标文件存在则直接清空
    >> 追加到文件末尾

    在 for 循环里用 > 每 grep 一次就清空一次 ip.txt ,当然没结果了
    winsweet
        25
    winsweet  
       2014-03-07 13:15:16 +08:00
    @webjin 不多, 你试一下就知道了.. 你是想要得到这样的结果:只在1.txt里出现过但没在ip.txt里出现
    pfipdaniel
        26
    pfipdaniel  
       2014-03-07 13:36:02 +08:00
    grep -vF ip.txt 1.txt
    webjin
        27
    webjin  
    OP
       2014-03-07 14:55:27 +08:00
    @winsweet 不是,我的意思是说 我知道某个段的一些IP在使用,然后统计出来,计算哪些IP没使用。
    webjin
        28
    webjin  
    OP
       2014-03-07 14:59:11 +08:00
    @pfipdaniel 你视乎没理解我的意思。 比如 192.168.0.1-255 这是一个段IP
    然后你们你们公司交换机里面 获取到了哪些IP在使用,然后你再去统计哪些IP没使用。
    saihuang
        29
    saihuang  
       2014-03-07 16:11:25 +08:00
    两个文件
    saihuang
        30
    saihuang  
       2014-03-07 16:14:12 +08:00
    楼主用if $?判断一下grep的返回,就知道这个ip在没在用了,然后单独输出到一个文件里
    vzex
        31
    vzex  
       2014-03-07 16:16:02 +08:00
    awk -F"." '{a[$4]="1"} END{for(i=1;i<=255;i++){if(a[i]!="1"){print "not used:192.168.0." i} else {print "used:192.168.0." i}} }' 1.txt
    不需要ip.txt
    vzex
        32
    vzex  
       2014-03-07 16:25:35 +08:00
    grep -v "$ip" ip.txt > ip.txt 你这个txt变空的原因是,重定向,会把ip.txt清空,才执行grep
    nanpuyue
        33
    nanpuyue  
       2014-03-07 16:42:57 +08:00
    其实可以不依赖ip.txt:
    seq -f "192.168.0.%g" 255 | grep -vf 1.txt - > ip.txt
    pfipdaniel
        34
    pfipdaniel  
       2014-03-07 17:25:32 +08:00
    @webjin grep -vwF -f 1.txt ip.txt
    webjin
        35
    webjin  
    OP
       2014-03-07 19:02:23 +08:00
    @nanpuyue 这个方法不行,我试了下,结果会不正确的
    BOYPT
        36
    BOYPT  
       2014-03-07 19:58:45 +08:00
    这有很难么,用不着顺序的ip.txt,直接seq生成间隙数组:


    1.txt如下:
    192.168.0.9
    192.168.0.11
    192.168.0.14
    192.168.0.126
    192.168.0.18

    命令执行:

    (for U in $(awk '{split($0,a,".");print a[4]}' 1.txt|sort -n) 255; do seq $BEG $((U-1)) | sed 's/^/192.168.0./'; BEG=$((U+1)); done) > r.txt

    结果:

    $ wc -l 1.txt r.txt
    5 1.txt
    249 r.txt
    254 total


    有249个可用地址,逻辑无误。
    BOYPT
        37
    BOYPT  
       2014-03-07 20:00:14 +08:00
    哦,上面我漏掉了手敲的初始变量BEG=1

    BEG=1;
    (for U in $(awk '{split($0,a,".");print a[4]}' 1.txt|sort -n) 255; do seq $BEG $((U-1)) | sed 's/^/192.168.0./'; BEG=$((U+1)); done) > r.txt
    nanpuyue
        38
    nanpuyue  
       2014-03-08 18:07:21 +08:00
    @webjin 嗯?我也试过了,貌似没问题啊,你的问题出在哪里?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2740 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 00:22 · PVG 08:22 · LAX 16:22 · JFK 19:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.