【问题标题】:Host file make a unique file for all servers主机文件为所有服务器创建一个唯一文件
【发布时间】:2017-09-28 23:53:44
【问题描述】:

我有很多主机文件。我从所有服务器收集它们并将它们放在 host_files.txt 中,然后我必须为所有服务器制作一个主机文件。

我执行此命令是为了创建一个唯一的文件,但有些行共享相同的 IP 地址或主机名。

awk '!a[$0]++' host_files.txt

这是我的 host_files.txt

#backup server IPs
95.23.23.56
95.23.23.57 

#ftp server IPs
45.89.67.5 
45.89.67.3 

#apache
12.56.35.36 
12.56.35.35 

#ftp server IPs
95.23.23.50

#apache
12.56.35.37 

我想输出文件,但我需要保留注释行

#backup server IPs <= comment line, i need to keep them
95.23.23.56 
95.23.23.57 

#ftp server IPs <= comment line, i need to keep them
45.89.67.5 
45.89.67.3 
95.23.23.50

#apache <= comment line, i need to keep them
12.56.35.36
12.56.35.35 
12.56.35.37

我已经试过了:

sort -ur host_files.txt

cat host_files.txt | uniq > ok_host.txt

我需要没有#的ip只需要ip地址请帮助我

提前致谢

【问题讨论】:

    标签: sorting awk


    【解决方案1】:

    在 GNU awk 中使用多维数组:

    $ awk '
    /^#/ { k=$0; next }          # group within identical comments, k is key to hash
    /./  { a[k][$1]=$0 }         # remove empty records and hash ips
    END  { for(k in a) {         # after everything, output
               print k
               for(i in a[k]) 
                   print a[k][i]
         }
    }' file*
    #apache
    12.56.35.35 #apacheprivate
    12.56.35.36 #apachepub
    12.56.35.37 #apachepub
    #ftp server IPs
    45.89.67.3 #ftpssh
    45.89.67.5 #ftpmain
    95.23.23.50 #ftp
    #backup server IPs
    95.23.23.56 #masterbasckup
    95.23.23.57 #agentbasckup
    

    由于for(k in a),输出是随机顺序的,即。评论组和组内的 ip 没有特定的顺序。

    【讨论】:

    • @James Brown 感谢您的回复,但对我不起作用。我尝试 "awk '/^#/{k=$0;next}/./{a[k][$1]=$0}END{for(k in a){print k; for(i in a[k] ) print a[k][i]}}' host_files.txt 我有这个错误信息:语法错误上下文是:>>> /^#/{k=$0;next}/./{a[k][
    • 你有 GNU awk 吗?
    • 我可以使用 nawk 吗?
    • 抱歉,不得不出去一会儿。如果您使用 nawk,请尝试使用 @EdMorton 的解决方案。我的只适用于 GNU awk。另外,如果可能,请考虑查看 gawk,它有一些不错的功能。
    • 因为您使用IP地址作为key,如果IP被提及两次,您可能会失去注释。
    【解决方案2】:

    这适用于任何 awk:

    $ cat tst.awk
    /^#/ { key = $0; next }
    NF && !seen[$0]++ {
        ips[key] = ips[key] $0 ORS
    }
    END {
        for (key in ips) {
            print key ORS ips[key]
        }
    }
    
    $ awk -f tst.awk file
    #apache
    12.56.35.36 #apachepub
    12.56.35.35 #apacheprivate
    12.56.35.37 #apachepub
    
    #ftp server IPs
    45.89.67.5 #ftpmain
    45.89.67.3 #ftpssh
    95.23.23.50 #ftp
    
    #backup server IPs
    95.23.23.56 #masterbasckup
    95.23.23.57 #agentbasckup
    

    由于使用in 运算符,输出顺序将是随机的,如果这是一个问题,只需更改几行代码即可。

    【讨论】:

    • 那太好了。
    【解决方案3】:

    如果不需要 awk。

    #!/bin/ksh
    
    cat host_files.txt | while read line ; do
        [[ $line =~ ^$ ]] && { continue; }              # skip empty lines
        [[ $line =~ ^# ]] && { group=$line; continue; } # remember the group name
        print "$group|$line"                            # print with group name in front
    done | sort  \
        | while read line ; do
            if [[ ${line%\|*} != $last ]]; then         # if the group name changed
                print "\n${line%\|*}"                   #  print the group name
                last=${line%\|*}                        #  remember the new group name
            fi
            print "${line#*\|}"                         # print the entry without the group name
        done
    
    • 将组名放在行前
    • 排序
    • 检测更改组名并打印出来
    • 打印不带组名的条目

    使用与 awk 相同的概念(避免 shell 中的 while 循环)。

    awk '
        /^#/ { k=$0; next }
        /./  { print k "|" $0 }
    ' host_files.txt |   sort   | awk -F '|' '{
            if ( k != $1 ) { print "\n" $1; k = $1; }
            print $2
        }' -
    

    因为它不使用数组,所以不会因为重复键而导致行松散。

    而且,再想一想,第二个 awk 是可以避免的。将密钥添加到每一行。对于没有“x”的标题。所以标题排在其余部分之上。在输出中,只需删除添加的排序键。

    awk '
        /^#/ { k=$0; print k "|" $0; next; }
        /./  { print k "x|" $0 }
    ' t18.dat  |   sort -u   | cut -d '|' -f 2
    

    【讨论】:

    • 无论是否需要 awk,它都是适合该工作的工具。请参阅why-is-using-a-shell-loop-to-process-text-considered-bad-practice 了解一些原因(以及谷歌 UUOC)。
    • 您对 UUOC 的看法是正确的。但它使数据流更加明显(好吧,这不是最有力的论据)。
    • 只是想添加一种不同的方法,而不是将整个输入读入内存并在最后打印。但是两个 awk 运行和一个排序在中间可能是值得的。
    • @ULick 抱歉,脚本工作正常,但有很多重复行
    • 您确定它们不在输入中吗?可以通过在排序中添加-u 来删除重复项
    猜你喜欢
    • 2011-10-18
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    相关资源
    最近更新 更多