
Improving CLIs with isatty - jez
https://blog.jez.io/cli-tty/
======
rlpb
Please be careful with this. From the GNU Coding Standards:

"...please don’t make the behavior of a command-line program depend on the
type of output device it gets as standard output or standard input."

[https://www.gnu.org/prep/standards/standards.html#User-
Inter...](https://www.gnu.org/prep/standards/standards.html#User-Interfaces)

Of course you don't have to follow their standards, but their rationale for
this particular item is reasonable.

I think a warning as described in the article is perhaps just about OK though.

~~~
Normal_gaussian
OK until, of course, you meet me.

And I go around piping things into 'less -RS'

I wouldn't get the warning.

Though of course getting it to some is probably better than none so I'm more
than likely with you.

\--

Unfortunately many apps do behave differently towards ttys in one key way -
colour.

It is somewhat frustrating to be piping into less something like 'apt list
--upgradable' and being unable go essuly scan because its a mess without
colour.

~~~
jancsika
Instead of a warning it could grep the contents of the current directory. I
bet that would work if you were imagining a use case of typing your pipeline
on the command line.

------
mbreese
I haven’t figured out a way to do this in native Java, so I end up wrapping my
Java CLI tools in a bash wrapper (as a self executing JAR). This wrapper’s
main purpose is to set a Java property based on the results of the bash test:

    
    
        if [ -t 0 ]; then
        fi
    

I then use this flag to know if I should do things like export CLI progress
bars or other interactive things.

~~~
skissane
You can call isatty() using a Java FFI library such as JNA or JNR. Some day,
Java will come with this out-of-the-box and an external library will not be
needed – see
[https://openjdk.java.net/jeps/191](https://openjdk.java.net/jeps/191)

For JNA (probably JNR too, my personal experience is only with JNA though),
just have to add the JAR to your project (or the Maven/Gradle dependency). The
JAR includes native libraries for various platforms.

It is non-portable, it won't work on Windows, although you may not care about
that, and if you do, Windows has similar APIs (e.g. calling GetConsoleMode()
on the file handle will fail if the handle doesn't point to a console.)

~~~
tyingq
Jansi might be worth a look. Provides isatty() and other things that might be
helpful for a Java command line app. Works on Windows also.
[https://github.com/fusesource/jansi](https://github.com/fusesource/jansi)

------
peterwwillis
The problem with doing this is you end up with a bunch of tools which may or
may not have unexpected behavior depending on how you ran them. It's better to
have a simple design that just works one way, and you're forced to use it in
the one right way. When users invariably use it the wrong way, the reasoning
about the failures is simpler, and there are no extra bugs from the extra
lines of guard-rail code.

If you really wanted to add this 'protection code', you could make a bash
wrapper around every Unix command that has its input or output connected to a
tty. Not perfect, but it would eliminate a whole lot of extra tty-checking
code from every app, providing a single reliable interface. I imagine you'd
turn it off after a while, though.

------
quietbritishjim
> the isatty function in the C standard library (man 3 isatty)

It is not in the C standard library, it's in POSIX so isn't available in
non-*nix platforms. The same problem applies in other languages using it
through cffi.

------
loeg
isatty on which standard file, though, takes some consideration. Zero, any,
some, or all of stdin, stdout, and stderr may be redirected independently.
Some programs might usefully print differently redirected into a file vs
rendered on a tty. And what is one to do about pipes?

~~~
juped
no, this only makes any sense at all for stdin

~~~
the8472
it also makes sense for stdout, e.g. when you're spewing binary data that
might corrupt a terminal.

~~~
juped
No it doesn't - why would it help at all to precede that with a warning the
user wouldn't see?

------
fao_
The implementation in musl libc is a simple ioctl call[0], so really it should
be available in all languages without need for a C FFI. I always find this
kind of thing interesting.

[0]: [https://git.musl-
libc.org/cgit/musl/tree/src/unistd/isatty.c](https://git.musl-
libc.org/cgit/musl/tree/src/unistd/isatty.c)

~~~
skissane
ioctl is inherently non-portable. Even though most Unix-like OS implement it,
it is not part of the POSIX / SUS standard and so code which relies on it is a
portability problem. The problem is the ioctl command codes and their
parameters are not standardised and vary from OS to OS.

(The POSIX standard does standardise ioctl, but only for use with STREAMS,
which is an optional feature which more often than not isn't implemented.)

~~~
cperciva
Just to be clear, while ioctl has issues, isatty is part of the POSIX
standard:
[https://pubs.opengroup.org/onlinepubs/9699919799/functions/i...](https://pubs.opengroup.org/onlinepubs/9699919799/functions/isatty.html)

------
jessaustin
There were some interesting suggestions along these lines in the "12 factor
CLI" piece previously linked at HN, in sections 6 and 7:

[https://medium.com/@jdxcode/12-factor-cli-apps-
dd3c227a0e46#...](https://medium.com/@jdxcode/12-factor-cli-apps-
dd3c227a0e46#cca8)

