7
\$\begingroup\$

I am working with MongoDB through Docker, and I have a terrible bash command to pull the Docker Machine IP so I can sanely connect locally.

export dockerip="$(docker-machine ls | awk '{print $5}' | sed -n '2p' | sed 's/tcp:\/\///' | sed 's/\:2376//')"
mongo --host "$dockerip" --port 27017

How can I optimise the docker-machine line?

\$\endgroup\$
4
\$\begingroup\$

You can reduce the number of commands in it.

First of all, it's easy to combine these two commands:

awk '{print $5}' | sed -n '2p'

This is exactly the same:

awk 'NR == 2 {print $5}'

It's also easy to combine the two other sed commands:

sed 's/tcp:\/\///' | sed 's/\:2376//'

Like this:

sed -e 's/tcp:\/\///' -e 's/\:2376//'

By doing so you reduce the number of processes to run, making the pipeline of commands more efficient.

These last sed commands can be written a bit simpler by using a different separator character, and avoiding unnecessary escapes:

sed -e 's?tcp://??' -e 's/:2376//'

And the last term might be better more generalized:

sed -e 's?tcp://??' -e 's/:.*//'

Putting this all together:

export dockerip="$(docker-machine ls | awk 'NR == 2 {print $5}' | sed -e 's?tcp://??' -e 's/:.*//')"

You could actually still go further, and completely eliminate sed by moving those operations into awk. But this is already much more efficient than the original, simple, and probably good enough.

\$\endgroup\$
  • \$\begingroup\$ Cool, thanks! This was a chance for me to learn sed better. :) \$\endgroup\$ – mxplusb Sep 18 '15 at 14:52
5
\$\begingroup\$

docker-machine provides a simple way to get the IP of the host machine

mongo --host `docker-machine ip default` --port 27017

I'm using default here, since that's the name of the machine I'm using.

\$\endgroup\$
3
\$\begingroup\$

This is a good example of how Bash (and ksh) are capable of 99% of the sed/awk/grep/cut gymnastics that many of us perform. One awk and one sed is pretty good and easy enough to understand, but if you want to do this without any external processes, it can be done.

Apart from performance, if you do it all in the shell your script is more portable.

First you can use read in a loop to get a chosen field from a chosen line:

line_number=1
while read f1 f2 f3 f4 f5 fx
do
    if [ $line_number -eq 2 ]; then
        break
    fi
    (( line_number++ ))
done < <( docker-machine ls )  # Process Substitution into a loop, fun!

Then you can use BASH_REMATCH to save part of a regular expression match:

dockerip=
if [[ "$f5" =~ tcp://([^:]+):[0-9]+ ]]; then
    dockerip=${BASH_REMATCH[1]}
fi
\$\endgroup\$
  • \$\begingroup\$ Upvoting due to portability and because I didn't know Bash did REs. \$\endgroup\$ – mxplusb Oct 21 '15 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.