将Redis添加到/ etc / services的最优雅方法是什么?

时间:2015-04-23 19:52:23

标签: shell redis

所以今天,2015年4月23日,互联网号码分配机构已经颁布了port 6379Redis的使用,这确实是一个巨大的日子!

我希望com·mem·o·通过在我的/etc/services文件中添加以下行来评价这个精彩的场合:

redis     6379/tcp

最好的方法是什么?当然,我的意思是,以下内容:

  1. 毋庸置疑,新行应该插入适当的位置(例如,在我的系统gnutella-rtr 6347/udp之后的Assigned Numbers块下面)
  2. 我考虑过使用各种文本编辑器,但感觉不合适
  3. 理想情况下,解决方案应该是可复制的单行
  4. 我可以设想awk脚本可以做到这一点,但我正在寻找更多的东西,某个je ne sais quoi
  5. 更新了@Markus'sed提案:我担心问题会在其他系统上应用此“修补程序”,而这些系统不一定具有相同的/etc/services文件所以,在上面的第1点扩展,解决方案必须确保无论文件中前置服务的具体细节如何,都要保留订单。

    更新2:对于状态似乎很重要的几点 - a)虽然不是强制性的,但解决方案的长度(或缺乏相当)肯定是其优雅的重要部分(类似于外部依赖性) [即缺少这些]); b)我/我们假设/etc/services已被排序,但看到它不会发生时会发生什么事情会很有趣; c)假设您具有root权限并小心rm / -rf命令。

7 个答案:

答案 0 :(得分:9)

单行排序,将其放在正确的位置:

echo -e "redis\t\t6379/tcp" | sort -k2 -n -o /etc/services -m - /etc/services

答案 1 :(得分:3)

规则中没有任何内容可以回答我自己的问题 - 这个只使用Redis

cat /etc/services | redis-cli -x SET services; redis-cli --raw EVAL 'local s = redis.call("GET", KEYS[1]) local b, p, name, port, proto; p = 1 repeat b, p, name, port, proto = string.find(s, "([%a%w\-]*)%s*(%d+)/(%w+)", p) if (p and tonumber(port) > tonumber(ARGV[2])) then s = string.sub(s, 1, b-1) .. ARGV[1] .. "\t\t" .. ARGV[2] .. "/" .. ARGV[3] .. "\t\t\t# " .. ARGV[4] .. "\n" .. string.sub(s, b, string.len(s)) return s end until not(p)' 1 services redis 6379 tcp "remote dictionary server" > /etc/services

格式化Lua代码:

local s = redis.call("GET", KEYS[1])
local b, p, name, port, proto

p = 1
repeat
    b, p, name, port, proto = string.find(s, "([%a%w\-]*)%s*(%d+)/(%w+)", p)
    if (p and tonumber(port) > tonumber(ARGV[2])) then
        s = string.sub(s, 1, b-1) .. ARGV[1] .. "\t\t" .. ARGV[2] 
        .. "/" .. ARGV[3] .. "\t\t\t# " .. ARGV[4] .. "\n" 
        .. string.sub(s, b, string.len(s))
        return s
    end 
until not(p)

注意: 类似的挑战(https://gist.github.com/jorinvo/2e43ffa981a97bc17259#gistcomment-1440996)激发了这个答案。我选择了一种纯粹的Lua脚本方法而不是利用排序集...虽然我可以:)

答案 2 :(得分:2)

一个python脚本,Itamar怎么样?

它适用于提取端口号的概念(在代码中称为索引),如果我们高于6378但尚未打印我们的Redis线,则打印它,然后将该sentinel标记为true并打印所有线(包括我们所在的那个。)

#!/usr/bin/python
lines = open("/etc/services").readlines()
printed=False
for line in lines:
    if printed:
        print line.rstrip()
        continue
    datafields = line.split()
    if line[0] == "#":
        print line.rstrip()
    else:
        datafields = line.split()
        try:
            try:
                index,proto = datafields[1].split("/")
                index = int(index)
            except:
                index,proto = datafields[0].split("/")
                index = int(index)
            if index > 6378:
                if not printed:
                    print "redis           6379/tcp    #Redis DSS"
                    printed = True
            print line.rstrip()
        except:
            print datafields
            raise

我文件中的相关部分用于比较:

gnutella-rtr    6347/tcp    # gnutella-rtr
#                          Serguei Osokine <osokin@paragraph.com>
#               6348-6381  Unassigned
redis           6379/tcp    #Redis DSS
metatude-mds    6382/udp    # Metatude Dialogue Server
metatude-mds    6382/tcp    # Metatude Dialogue Server

请注意,Redis上方的行是一个范围。如果没有突破这个范围,这对我来说是一个可行的解决方案。你可以打破范围,但IMO就可以了。对于一个简单,优雅的脚本来说,拆分范围似乎有点多了。特别是考虑到大多数服务文件没有列出未分配范围的可能性(这是在OS X上) - 并且它们仍然在评论中。

更新

如果您不关心本地文件及其注释,这将为您提供所有当前分配的端口,这些端口不是保留或丢弃的: curl -s http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.csv| awk -F',' '$4!~/(Discard|Unassigned|Reserved)/ && $1 && $2+0>0 && $1!~/FIX/ {printf "%-16s\t%s/%s\t#%s\n", $1,$2,$3,$4}' > /etc/services

FIX测试是因为其中一些行已经嵌入了换行符 - 这可能是awk的痛苦。

答案 3 :(得分:2)

按顺序插入6379的幂等awk单行将是:

awk -v inserted=0 '/^[a-z]/ { if ($2 + 0 == 6379) { inserted=1 }; if (inserted == 0 && $2 + 0 > 6379) { print "redis\t\t6379/tcp"; inserted=1 }; print $0 }' /etc/services > /tmp/services && mv /tmp/services /etc/services

答案 4 :(得分:2)

真正的男人不使用sed / awk:)

TMP_SERVICES=/tmp/services.$RANDOM

while read line
do
  printf %b "$line\n" >> $TMP_SERVICES
  if [[ $line == *"6347/udp"* ]]; then
    printf %b "redis\t\t6379/tcp\n" >> $TMP_SERVICES
  fi
done<"/etc/services"

mv -fb $TMP_SERVICES /etc/services

答案 5 :(得分:1)

sed -i '/6347\/udp/a redis     6379\/tcp' /etc/services
祝你好运!

更新

sed -i '/6347\/udp/a redis \t\t 6379\/tcp' /etc/services

看起来更好......

更新2

洛尔

sed -i ''"$(echo $(echo $(grep -n $(awk {'print$2'} /etc/services | awk -F "/" '$1<6379'{'print$1'} | tail -1) /etc/services | awk -F ':' {'print$1'}|tail -1) + 1)|bc)"'i redis \t\t 6379\/tcp' /etc/services

答案 6 :(得分:1)

我喜欢sed的就地替换,所以我将它与awk搜索services

中的下一行结合起来
R="redis\t\t6379/tcp\t\t\t# data structure server" N=$(awk '{if($2+0 == 6379) exit(1);if ($2+0 > 6379) {print $0;exit(0)}}' /etc/services) && sed -i "s~$N~$R\n$N~" /etc/services