1

If I execute echo this | docker run -i alpine cat, I get this.
If I execute docker run -i alpine cat, I get blocked terminal, because cat reads stdin, but there is nothing there.

I can check opened file descriptors. If I run docker run -i alpine ls -lA /proc/1/fd, I get this in stdout:

lr-x------    1 root     root            64 Aug  9 13:45 0 -> pipe:[10289389]
l-wx------    1 root     root            64 Aug  9 13:45 1 -> pipe:[10289390]
l-wx------    1 root     root            64 Aug  9 13:45 2 -> pipe:[10289391]
lr-x------    1 root     root            64 Aug  9 13:45 3

and this in stderr:

ls: /proc/1/fd/3: cannot read link: No such file or directory

With echo this | docker run -i alpine ls -lA /proc/1/fd everything is the same (except pipe:[these numbers]).

If I'm not removing -i from docker run, is there any way I can check if there is any data in stdin without IO block? test -t 0 simply doesn't work, because stdin fd is always opened.


I want to make a CLI command (via docker run mycommand) that reads from stdin and outputs to stdout (stdout is simple, nothing interesting there). So, I want echo data | docker run mycommand which will print out something different based on the input data. But if I were to do docker run mycommand it should say that I "need to provide data to stdin" for it to work.

1 Answer 1

0

Yes you can determine if there is any data to be read, in shell. I saved a LOT of information on shell input reading in.

https://antofthy.gitlab.io/info/shell/input_reading.txt

Your question... "is there any way I can check if there is any data in stdin without IO block?"

You are basically asking for 'poll' (no read) test...

read -r -t 0 var

This does not actually read anything. Its exit status is 0 (true) if there is something to read otherwise it returns 1 or false if there isn't or it is EOF.

Also NOTE this only tells you if there is data. It does not tell you if the input is at "End of File" (EOF) until you try to read. Nor does it tell you if the input is a complete line (with a newline).

To read the available data without blocking...

  read -r -t 0.00001 line

Remember most things read a whole line, and will typically block on input until it gets a Newline character or EOF. The above will return a error exit of 142 and a empty line, if no newline is available, even for a incomplete line followed by EOF.

To read all data even available newline or not (any newlines will be included)...

  while IFS= read -r -s -d '' -t .01 data
  do [ $? -ge 128 ] && break
    printf "$data"
  done

Adding a -n1 to the read will do it one character at a time!

I recommend going though the various sections of the above document to figure out what you want. All of it can apply equally well to any other programming language according to that languages eccentricities.

Extra

You may also like to look at a perl script I wrote called "shell_select", which allows you to check if any listed file descriptors are ready for read or write, from shell!

https://antofthy.gitlab.io/software/#shell_select

I have used it to handle MULTIPLE input streams (stdout and stderr from a raw "bc" math calculator) without it hanging (blocking) on one or the other file handles, while still keeping the to inputs completely separate.

2
  • I probably didn't know about -t for read because it's not POSIX. It will be great if you can include a POSIX solution. I'm very busy, but I hope I will be able to read your file.
    – Andrew15_5
    Commented Dec 12, 2023 at 5:37
  • 1
    Posix is limited... in which case you will need to do the equivalent in C or perl, to avoid those posix limitations. Bash is now near universal in any case. Even Mac's which tend to be well behind updated its bash when the Shell Shock Bug was discovered!
    – anthony
    Commented Mar 15 at 0:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .