Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the most elegant way to add Redis to /etc/services?

Tags:

shell

redis

So today, April 23rd 2015, the Internet Assigned Numbers Authority had decreed the use of port 6379 to Redis, a frabjous day indeed!

I wish to com·mem·o·rate this splendid occasion by adding the following line to my /etc/services file:

redis     6379/tcp

What would be the best way to go about it? By best I mean, of course, the following:

  1. Needless to say, the new line should be inserted in its proper place (i.e.g. under the Assigned Numbers block, right after gnutella-rtr 6347/udp on my system)
  2. I've considered the use of various text editors, but it feels out of place
  3. Ideally, the solution should be a copy-pastable one-liner
  4. I can envision the awk script that could do that but I'm looking for something more, a certain je ne sais quoi

Update re @Markus' sed proposal: I'm afraid the problem would be applying this "patch" on other systems that do not necessarily have the same /etc/services file so, expanding on point #1 above, the solution must ensure that regardless the specifics of to-be-preceding service in the file, order is kept.

Update 2: a few points that seem important to state - a) while not mandatory, the solution's length (or lack of rather) is certainly an important part of its elegance (similarly for external dependencies [i.e. lack of these]); b) I/we assumed that /etc/services is sorted, but it would be interesting to see what happens when it isn't; c) assume that you have root privileges and be careful with that rm / -rf command.

like image 627
Itamar Haber Avatar asked Apr 23 '15 19:04

Itamar Haber


3 Answers

A single line sort that puts it in the right place:

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

like image 178
Ofir Luzon Avatar answered Oct 24 '22 02:10

Ofir Luzon


Nothing in the rules against answering my own question - this one uses Redis exclusively:

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

Formatted Lua code:

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)

Note: a similar challenge (https://gist.github.com/jorinvo/2e43ffa981a97bc17259#gistcomment-1440996) had inspired this answer. I chose a pure Lua script approach instead of leveraging Sorted Sets... although I could :)

like image 3
Itamar Haber Avatar answered Oct 24 '22 01:10

Itamar Haber


An idempotent awk one-liner that inserts 6379 in order would be:

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
like image 2
djanowski Avatar answered Oct 24 '22 00:10

djanowski