If I want to send a string over TCP in a shell environment, I can do something like:

echo text | nc 9876

Cool. Interactively, that works. Now I want to do this programmatically by spawning a subprocess from another program, so I want to avoid using a shell and pipes.

Also, since I'm deploying with distroless Docker containers, they don't come with a shell.

Is there an existing tool to send an command argument as string over TCP? I'm looking for an (imaginary) variant of nc, e.g.:

nc 9876 text

that does the same as

echo text | nc 9876

(Need the output too.)

I'm about to write my own application for this, but I can imagine this exists already, simply taking one of the argv instead of stdin to pass on.

Looked at socat, which can read from files with OPEN, which is very close to what I want, but I need the string to be passed as parameter from the command issued.

For the full context, the entrypoint of the Docker container should be settable by it, without shells or other interpreted language, but pure OS native dependencies like glibc (like socat/nc is!).

  • 2
    If you haven't got a shell, what are you expecting to run your command ? – X Tian Mar 26 at 10:26
  • you must have somekind of shell if you can run netcat inside your docker. Don't you have access to busybox echo or busybox cat commands ? – Kiwy Mar 26 at 10:46
  • @XTian Uhm, you can run commands without a shell! In fact, that's what best practice in containerized environments. E.g. ENTRYPOINT ["/bin/sh", "-c", "mycommand"] is unnecessary, just do ENTRYPOINT ["mycommand"]. Also more generally, when processes spawn other processes, you don't want to invoke a full shell, see e.g. man 2 execve. – gertvdijk Mar 26 at 11:30
  • 1
    Please read your question you need to use | to execute your command, pipe is part of the shell so you either need a shell/bash/zsh to execute your command either you develop a module to nc to allow the use of a file as an argument. So if you have a busybox inside you can use busybox sh. Distroless is oriented toward application execution so you could either use a python application to do what you want stackoverflow.com/q/1908878/1195001 or use an other docker image as it seems this one doesn't fulfil your goal. – Kiwy Mar 26 at 12:23
  • 2
    So you have some restriction on the collection of programs available in your docker environment, and you want someone to guess which of those programs can do the work of reading from a socket and writing to it, and also spawning some other program. It would then help if you then tell which programs you do have rather then telling some you don't have. – Ralph Rönnquist Mar 26 at 12:24

I don't know of any program that takes a parameter and sends it over a tcp connection.

However you have sort of answered your own question somewhat within your comments, specifically with the following line.

ENTRYPOINT ["/bin/sh", "-c", "mycommand"]

I appreciate that you seem to want the minimalist footprint of applications in your image, but I believe the best solution is to have a shell and netcat., then use your original command. Well at least to test whatever you are trying to do.

If at the end of the day, you want to drop back to only one executable, you'll have to write your own program to do it.

One thought, I see this example, shows setup of Python to run a script,

FROM python:2.7-slim AS build-env
ADD . /app

FROM gcr.io/distroless/python2.7
COPY --from=build-env /app /app
CMD ["hello.py", "/etc"]

which might be easier/quicker than developing a C program to do it all, but then effectively you are using Python as the SHELL. Lastly, if you think socat would do what you want, could you use socat to read from a file (which you include in your image), and that file contains your literal string.

  • This is not an answer to my question, sorry. I was asking if there was a program already that implements the 10 lines of C code to write arguments to a socket, instead stdin. – gertvdijk Mar 26 at 14:06
  • I started my answer saying I don't think there is such a program, and then went on to suggest alternative solutions. I also think having a couple of utilities (shell, php, busbox) still constitutes a distroless container, minimising the the available targets. – X Tian Mar 26 at 14:16

I suppose you could use newlisp, such as

newlisp -e '(write-line (net-connect "localhost" 3456) "go for it")'

and vary parameters as desired.

I'm pretty sure you could use perl or other interpreters as well, though newlisp is quite small and it can be compiled into a static program as well.

The above example will make the program connect to localhost port 3456, and issue the line go for it on the socket, then it will exit. Goto the newlisp home site for more details.

  • JRE ?? Not sure where you got that one from. – Ralph Rönnquist Mar 26 at 22:05
  • newlisp.org/index.cgi?Downloads shows a JRE dependency to me? – gertvdijk Mar 26 at 22:08
  • It's a bit of bad advertising, I think :) Of course one can run newlisp with a Java process as a front-end, if it's too hard to do terminal interaction. But that is newlisp plus a front-end. You don't want/need a front-end, esp. as you want to execute only the command line script. – Ralph Rönnquist Mar 26 at 22:12
  • Oh, yeah I see it now. The JRE is for development. I see that the actual binary is quite lightweight, thanks. Still, some libreadline I see I don't have in the container, but yeah, close enough for an answer! – gertvdijk Mar 26 at 22:13
  • Yes. Normal build requires libreadline, libffi and libdl. Though it's quite easy to build a binary without needing any of them (and lose the related functionality of course). Ask at newlispfanclub.alh.net if you need. – Ralph Rönnquist Mar 26 at 22:33

I've written my own small application to implement what I need. Reads arguments and writes them to a socket. Too bad that it didn't exist yet, but only more complicated features are available in tools like nc and socat. Perhaps I might find time to write a patch to nc to also accept input from an argument.

Re comments - I find it a bit sad to read including a full shell and spawning subprocesses from it is the new norm. Pure overhead we don't need.

  • 2
    Instead of writing such a narrow utililty, you could've written a wrapper that "transforms" some command line arguments into a file and then exec's another program with its stdin redirected from it. Simple POC (linux-only) here. You can use it as herestring text nc -N host port. (that will not append a newline to text, unlike echo text). – mosvy Mar 26 at 23:29
  • @mosvy Oh wow, that's very helpful, thanks! You could make that into an answer and I would accept it. – gertvdijk Mar 28 at 9:03

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.