Useful output in CLI applications

I favored Nushell. I was using it for a few months, until I decided to switch back to good old ZSH. Why I did that is a separate story. However, I couldn’t get the idea of having quarriable outputs from CLI applications, off my mind. Look at this:Screenshot showing using the ls command

This is natural. However, it’s let’s say… difficult to have it in any other shell, with all the CLI applications out there.

Taking Nushell’s approach, you need to re-write all the applications out there to make sure it’s quarriable with this syntax. And then it’s difficult to keep it backward compatible (which caused me to say goodbye to Nushell).

What’s the problem?

Most of the CLI tools, output pure text, regardless of the context they are invoked in. The closest thing I can remember top of my head, is `aws-cli` where, you can define the output type to text or JSON using an argument, environment variable or configuration.

JSON?

Yeah, I hate it too, but it’s effective. We have the incredible jq, which enables us to dice it quite well.

There is also jc, which transforms the output of some well-known applications into JSON, making it possible to use them with `jq`.

An idea!

While developing a toy CLI application, I thought, what if as CLI application developers, we take it even further. Why not output the information, aware of the context, and choose the best (even opinionated ones) by default, while allowing the user to override it.

Did a bit of research, and learned this is possible with ‍‍`isatty` call in C. Would suggest reading this response on Stack Exchange. I was coding in Go, and found this package called go-isatty, which does the same thing.

So, how can it help my idea? Here:


if isatty.IsTerminal(os.Stdout.Fd()) {
	fmt.Print(message)
} else {
	js, err := json.MarshalIndent(info, "", "\t")
        if err != nil {
		panic("Failed to print json")
	}

	fmt.Println(string(js))
}

And this is how it looks like in action: asciicast

Pretty simple, hah? How does it work? The library I used up here, uses `IoctlGetTermios` which seems like (couldn’t find any descriptive docs around this) it returns a `Termios` struct, which contains information about the terminal. This only works on Linux, and there are a few other implementations in `go-isatty` which achieves the same goal in other operating systems.

Conclusion

Well, it seems it’s not that complex to have this feature baked in the CLI applications. Then the question would be, can we have a better query language for JSON, or can we have even a better data structure? Having that, it’s possible to turn any shell into a modern shell with useful features we see on Nushell.

Shahin 🧑‍🍳 Cooking data as a chef de partie at DataChef.co by day! 🪄 Avid coder inventing magic by night!

PGP Key: 647B060E41F18866D184DDCB95FDD72BE5157BA9


Discuss...