Hacker News new | past | comments | ask | show | jobs | submit login
Rich Command Shells (waywardmonkeys.org)
187 points by BruceM on Oct 10, 2014 | hide | past | favorite | 98 comments



Text is the universal interface. You can do things with it. You can strip it, cut it, transform it, send it to other places. Humans can read it, programs can read it, your printer can output it. It can be sent to web APIs, it can be stored anywhere. It's compressible, can be colored and can be copy-pasted and is infinitely extendable. Thousands of protocols run over it.

The command line works with text. The command line remains the best interface I've ever used. It's user friendly, composable and available everywhere. It's easy to automate and easy to extend.

I wish the "command line with pictures" idea would just go away already. It adds nothing for the general public. I can already view pictures on remote machines with X forwarding.

Command line with pictures never made it, because there are ten competing standards. With text, everybody just agreed on ASCII and now Unicode/UTF8. Text has hundreds of ugly clutches on top of it (Extended ASCII, ANSI, Escape codes, etc, etc). It still works. It's still simple. It has its problems, but nowhere near as many problems as GUIs.

Those who don't understand Unix are doomed to reimplement it... poorly.


Text isn't the universal interface in Unix, byte streams are. You can quite happily send non-textual control characters and such around in Unix, or pipe data containing NULLs from one process to another. 'Text' is a very seductive abstraction, but it's one of the most brutal to work with once you start interacting with the real world and have to give up on ascii and deal with encodings and unicode and so on.

Putting commands and data inline is a recipe for disaster and a million command injection exploits. The Unix philosophy has broken the minds of generations of programmers. It leads them to doing things like concatenating strings to build SQL queries or doing IPC with ad-hoc regex-parsed protocols or using a couple of magical characters to indicate that the contents of a variable should be parsed and executed instead of just stored. Take a read of some of the earlier threads on HN about Shellshock, and you will find numerous people blaming Apache for not "escaping" the data it was putting in a shell variable. As if it even could.

Even Unix nerds have at least partially internalised the dangerousness of the paradigm -- "don't parse the output of ls" and so on. The fact that the Unix paradigm (passing everything as strings with magical characters and escape sequences) is broken for the most fundamental computing tasks like working with file names ought to be a damning inditement of the paradigm. Sadly people merely parrot the rote learned lesson "don't parse ls because file names can't be trusted", without thinking about all the other untrusted data they expose to unix shells all the time.

Just this week Yahoo got exploited. At first people thought it was Shellshock, but no, it was just a routine command injection vulnerability in their log processing shell scripts. A problem blighting just about every non-trivial shell script ever written.

The usual reply is "don't use shells with untrusted data". But auditing where any particular bit of data came from can be just about impossible once it has been across several systems through programmes written in a variety of languages, stored on a file system, read back and so on. The only sane solution is to never use shell scripts.

Like the C memory and integer model makes writing secure C code borderline impossible, the Unix "single pipe of bytes that defaults to being commands" paradigm makes writing secure shell scripts borderline impossible.

Unix needs to be taken out back and shot.


> Putting commands and data inline is a recipe for disaster and a million command injection exploits. The Unix philosophy has broken the minds of generations of programmers. It leads them to doing things like concatenating strings to build SQL queries or doing IPC with ad-hoc regex-parsed protocols or using a couple of magical characters to indicate that the contents of a variable should be parsed and executed instead of just stored.

Yes! And then to compensate, they have to "sanitize" untrusted input to their systems. I had a meeting yesterday with a developer and a project manager at an organization that wants to work with my company to integrate one of our products with one of theirs. I mentioned the possibility of submitting some data in JSON format to a web API on their end, and the project manager asked about the risk of code injection attacks, by which he apparently meant SQL injection. I had to assure him, based on my knowledge of their tech stack (Node.js, CouchDB, and naturally, JSON) that code injection wouldn't be an issue. My point is that the common abuses of strings by Unix and web developers have led to well-known and widely feared security vulnerabilities which just don't exist in software that's built on a foundation of properly structured data.

See also this classic by Glyph Lefkowitz:

https://glyph.twistedmatrix.com/2008/06/data-in-garbage-out....


I would not be half as capable of troubleshooting in my work as I am if I couldn't parse random byte strings on the command line. That alone is why I use Unix for embedded development. Powerful things are often dangerous. For instance, consider nuclear power, motor vehicles, rocket engines, medicine, plastics, et. al..

So how do you provide the same level of capability as C and UNIX but without mixing data and commands? Is there some alternative paradigm that is just as powerful but safe?


Watch the Mathematica-backed StrangeLoop 2014 keynote by Stephen Wolfram. That's one way to think about it. There are others like how things work on the Lisp Machine (and somewhat similarly in CLIM).


> Take a read of some of the earlier threads on HN about Shellshock, and you will find numerous people blaming Apache for not "escaping" the data it was putting in a shell variable.

It seems to me that this is the result of Cargo Cult Programming. People know that SQL strings, and user input need to be 'escaped,' so they just think "Obviously this needs to be escaped too! It's user input!" Yet they don't realize that they are trying to put a square peg in a round hole. They just know that pegs go through holes, so they keep banging away at it.

Also, it's always amazed me that there was never some sort of 'standard' way to shell-escape things, even though the shell has been around for ages. Why can't I generate a shell string in the same way that I generate a SQL string? E.g.:

  sprintf("mv %t %t", src, dest);
Where "%t" is a special token that shell-escapes the input (e.g. "My File Name.txt" => "My\ File\ Name.txt"). Instead it's something where people continue to use ad-hoc, incomplete, of 'implemented everywhere' solutions to this.

Note: I don't generate SQL strings with sprintf(), but it's a close approximation of:

  execute('select * from table where id = ?', id);


SQL injection is not avoided by escaping arguments, but by never mixing the command and user supplied arguments in the first place. The equivalent to your example would be

  execlp("mv", "mv", src, dest, NULL);
which does not rely on the shell to try to untangle your arguments from a single string.

Edit: Fixed, thanks!


> SQL injection is not avoided by escaping arguments, but by never mixing the command and user supplied arguments in the first place.

People see:

  execute("select * from table where id = ?", id);
as for the most part like:

  execute(sprintf("select * from table where id = '%s'", escape(id)));
Where `escape()` is written by "smarter people" and makes sure that `id` isn't a string like this:

  0'; delete all from user;'
(e.g. turning it into `0''; delete all from user;''`). I realize that this isn't what actually happens, but the general idea is that you are sanitizing your inputs.


> Where `escape()` is written by "smarter people"

can we stop with this please? I'm sure it's not your intention and it's the way it's always phrased but it's casual contempt and we deserve to treat each other and be treated better.

"escape() is written by someone who spent the large amount of time analysing all the issues, testing, taking and incorporating feedback so the rest of us, who are both smart and competent, don't have to duplicate the work.


Similarly, no amount of escaping would protect you from Shellshock.

P.S. Doesn't execlp() require a NULL at the end of the parameter list?


Agree that text is being abused in Unix all the time. The problem with passing everything around as text is that you cannot reason about anything, because everything is of the same type. One big advantage of object-based systems is that they can catch type errors and notify you of the problem. Text pipelines will simply break because one of your implicit assumptions didn't hold.


"Like the C memory and integer model makes writing secure C code borderline impossible, the Unix "single pipe of bytes that defaults to being commands" paradigm makes writing secure shell scripts borderline impossible. Unix needs to be taken out back and shot."

What alternative do you advocate/propose ?

Genuinely curious ...


For the interactive general purpose data munging and quick execution of simple commands that the shell is best at, I really don't know what a better system would look like. It seems like a really hard problem. Anything purely text based ends up being fairly cumbersome to use for simple commands if it has to use real data structures (consider having to type (["a", "b"]) instead of a b to pass arguments with json style syntax or whatever). At least that was my experience of trying to write a very simple shell. There are a hell of a lot of people a hell of a lot smarter than me though.

It seems to me that a lot of shell scripts could be ported to other languages. Does DHCP on Linux need to use a shell script instead of python or something like that? The benefits of the shell grammar and semantics which are designed to make interactive use easy seem more like hindrances in a lot of those kinds of use cases. I assume it's largely done to make it easier for sysadmins to customise things. If I was a sysadmin I'd much rather learn python (and feel like I actually understood it) than the crazy byzantine grammar of bash. Maybe that's why I'm not a sysadmin.

This paper by Rob Pike might also be of interest: http://doc.cat-v.org/bell_labs/structural_regexps/se.pdf

>The current UNIX® text processing tools are weakened by the built-in concept of a line.


The reason the shell is used everywhere is because it's guaranteed to be installed (although DHCP used Bash explicitly), is much faster to start and run a simple script than Python, and its syntax is the command line that everybody should be familiar with.


I've hardly used it myself, but apparently Microsoft's PowerShell pipes typed objects between processes: http://technet.microsoft.com/en-us/library/dd347728.aspx


Actually, not between processes - all Powershell commands run in the same address space as the shell, and must be implemented in .Net. I don't think you can easily write an external process which takes a Powershell object directly as input.


Thanks for the correction, that explains so much--I was picturing a lot of DCOM craziness.


so in one corner: the ability to compose small, comprehensible functions with data streams, delivering staggering riches to the world.

in the other corner: the complaint that sometimes, people can put carriage returns in their filenames and screw up the output of `ls -1`. With no suggestion of what would replace composed functional streams.

Nice try Lennart.


> in the other corner: the complaint that sometimes, people can put carriage returns in their filenames and screw up the output of `ls -1`. With no suggestion of what would replace composed functional streams.

How about functions that operate on data structures such as lists and maps? These can include generic functions that can slice and dice data structures regardless of what type of data those structures contain.

> Nice try Lennart.

Is Mr. Poettering's name now an epithet to be thrown at anyone who opposes the Holy Unix Way? Or do you just know something I don't about the identity of the commenter to whom you were replying?


The unix dataset already works on list and map data structures.

lists: ls -1 | wc -l

maps: ps -ef | grep 'tobekilled' | grep -v grep | awk '{ print $2 }' | xargs kill

would unix be better if it were

cwd.files.count

and

processes.filter{name = 'tobekilled'}.map(kill)

?

maybe for the newbie who paradoxically already understands functional and object-oriented programming, I'll grant.

But the 'pipe' ("this is a bucket brigade") has always been pretty easy for people to grasp.

The Lennart bit was a joke. The OP's post was so histrionically overwrought that I responded sardonically. Apologies if you were offended.


I'm honestly not sure if your post is meant to be satire or not.

>lists: ls -1 | wc -l

The computer has taken a real array (probably an array in C), joined all the items together into one big string using magical characters as dividers, and then split it again on those magic characters to try and reconstruct the metadata that it threw away. I think the problem is pretty obvious and well known.

>would unix be better if it were cwd.files.count

Well, at least that is going to give you the correct result. Correctness seems like it should be pretty important, no?

Are you really arguing for shells being easier to learn using an example of a complicated command with 4 pipes, 2 different quoted strings, several single letter arguments, and that requires implicit knowledge about the structure of the output from several commands? Compared to a much shorter, simpler, type safe, and self documenting bit of code?

Also, yes my original post was hyperbolic. That was because I was responding to a histrionically overwrought post claiming that unix is perfect.


So your argument is that ls is not efficient enough in its implementation, but that you would suggest replacing all of that with an object model that implements the equivalent of Ruby's enumerable. Got it.

Shell is easy to learn because people innately understand "and then do this with it". You can start with ls, get to ls -1, then think, I want to count these, and get to wc -l.

Yeah, there are exceptions -- e.g., files with newlines in their name -- and yeah, the interface could use some cleanup. But pedagogically, I can assure you that teaching people shell is easier than teaching them map-reduce.


>So your argument is that ls is not efficient enough in its implementation

My complaint wasn't about the efficiency of ls, it was the fact that valuable information that is required for correctness is thrown away to achieve compatibility with the unix 'stream of text' interface and the attempt to recover that information leads to incorrect results. The paradigm is just fundamentally broken.

>you would suggest replacing all of that with an object model that implements the equivalent of Ruby's enumerable. Got it.

I don't even like Ruby at all (ironically, I find its grammar far too complex and shell-like to be able to parse in my head), so I've no idea what you are talking about. You seem to be assuming that everybody who dislikes the shell must be some strawman hipster.

>there are exceptions -- e.g., files with newlines in their name

I honestly find it extremely bewildering that any programmer would see that as being acceptable. It's not just that it fails to give the correct result, it fails silently. Silent data corruption is surely just about the worse class of bug.

>But pedagogically, I can assure you that teaching people shell is easier than teaching them map-reduce.

I presume you mean the functional ideas of map, reduce, and filter, not MapReduce ( https://en.wikipedia.org/wiki/Map-reduce ). The latter is irrelevant to the discussion.

My experience is the exact opposite. I found understanding the concepts of map and filter trivial. If you can understand a loop you can understand them. Reduce/fold isn't hard to understand either, although a bit tricker to make use of. Your example didn't use reduce anyway. Map and filter are typically much easier to use and reason about than a for loop in C, or a chain of commands in a shell script.

The shell is an absolute nightmare to learn. I have tried to learn to use it numerous times of the last decade or so, and I have always forgotten it the next time I come to do anything in the shell. The amount of knowledge you need to actually do anything is huge (the awk language, obscure and terse command names, complex regexes, memorising a bunch of command flags, memorising the output format of commands - usually a format designed for displaying to users rather than machine parsing, the shells ridiculously complex grammar, how to escape things etc etc) Your example illustrates that. It would have taken me 20 mins at least to put together that line of code you gave. Also, it's not like you escape having to understand concepts like map and filter. If you don't understand them (not necessarily by name) then you won't be able to write the line of unix commands you gave.

>Shell is easy to learn because people innately understand "and then do this with it".

People might find the concept of piping data easy to understand (I'm not convinced they do to be honest), but that alone won't do them much good because as your examples showed, you always need to run a bunch of complex and obscurely named commands, regex, or awk on the data to make the next command able to understand it.


>> there are exceptions -- e.g., files with newlines in their name

> I honestly find it extremely bewildering that any programmer would see that as being acceptable. It's not just that it fails to give the correct result, it fails silently. Silent data corruption is surely just about the worse class of bug.

Yes! We should strive to build our software on solid, non-leaky abstractions as much as possible, so that exceptions like a filename with an odd character in it just don't exist. Until we reach that point, computers will continue to frustrate their users for no good reason.


I didn't see any argument about performance. I only saw an argument about correctness.


> Well, at least that is going to give you the correct result. Correctness seems like it should be pretty important, no?

The devil is in the details. In OP's example, is "files" a field of "cwd," and "count" a field (or getter) of "files?" Is "filter" a method of "processes" and "map" a method of the resulting (implicit) list returned by "filter"?

If the answer to any of these is "yes," then you will find yourself needing to implement these fields and methods (and probably others) for each OS object. The "filter" in "processes" necessarily has a different implementation from "filter" in "files", since despite having the same external interface, they both operate in different contexts on different internal state (i.e. a process object is not a file object).

Contrast this with the UNIX approach, where the "filter" and "map" implementations (i.e. grep, awk, sed, tr) exist independent of OS-level objects (i.e. processes, files, semaphores, sockets, etc.) and their state, allowing them to be developed and improved independently of one another and the data they operate on.

You want there to be some notion of type safety and structure in IPC. This can already be achieved: simply rewrite your programs to communicate via asn.1, json, or protobufs, or some other common structured marshalling format. You can have ls send wc an array of strings, instead of having wc guess which bytes are strings by assuming that whitespace delimits them.

However, upon doing this, you will find that you will only be able to use wc with programs that speak wc's protocol. Now if you're lucky, you can convince everyone who wants to send data to wc to use the new protocol. If you're unlucky, you'll instead end up with a bunch of programs that only implement it partially or with bugs. If you're really unlucky, there will also be competing versions of the wc protocol. Moreover, what about programs that wc will need to pipe data to? wc will need to know how to communicate with all of them as well.

My point is, if we go the route of imposing structure and types on IPC, the only thing you'll have to show for it are O(N^2) IPC protocols for N programs, which they all must implement perfectly (!!) to get type safety. Want to write a new program? Now you also have to write O(N) additional IPC protocols so it can communicate with the others.

Maybe you can additionally mandate that each program speaks the same IPC protocol (i.e. there is One True Record for piping data in, and One True Record for piping data out). But, if this IPC protocol encompasses every possible use-case, how is it any different than a byte stream?


> ps -ef | grep 'tobekilled' | grep -v grep | awk '{ print $2 }' | xargs kill

versus

> processes.filter{name = 'tobekilled'}.map(kill)

Yes, actually, I would like the second one better (although I know it's only pseudo-code). To me, the most egregious problem with the Unix way of doing this is exemplified by the "grep -v grep" part. The first grep command didn't specify precisely what you wanted, i.e. the subset of processes whose executable name (or argv[0]) is "tobekilled". It can't, because ps produces lines of text intended primarily to be displayed on a terminal and read by a human, and grep merely searches those lines of text for a substring. It's all a very lossy process. So you had to add a second grep to work around the fact that the first grep also matched a particular occurrence of "tobekilled" in a command-line argument other than argv[0]. But what if someone were running "vim tobekilled.txt" at the same time? These sorts of workarounds are to Unix as epicycles were to Ptolemaic astronomy -- evidence that the foundation is flawed.

> maybe for the newbie who paradoxically already understands functional and object-oriented programming, I'll grant.

I think it would be easier to teach the fundamentals of functional programming -- not the crazy academic type-theory stuff, but basics like map and filter -- than all the intricacies and gotchas of combining Unix tools like grep, sed, cut, xargs, awk, and so on. You do realize that, in addition to the shell language itself, you casually dropped in a whole second language (Awk) in your second example, right?

> The Lennart bit was a joke. The OP's post was so histrionically overwrought that I responded sardonically. Apologies if you were offended.

It bothers me that you used Lennart's name as a synonym for "anti-Unix", as if that's his most salient characteristic (if it's even true of Lennart). How do you think he would feel about that "joke" if he read it? Especially on top of all the other vitriol he's received?


Don't get me wrong, tics like 'grep -v grep' are suboptimal, and indeed that's why people invented killall, and xargs -0, and so on. But in practice, there exist zero systems without workarounds and grotesqueries, and the unix philosophy, rather than any competing philosophy, is the entire reason why you're able to use any of the networks or computing devices you use today.

Can we do better? Sure! One could imagine a reformation of the unix philosophy to center around strongly typed streams that could totally work after you put about 20 years of effort into replacing the existing tools. All too often, though, the reformers are people who don't understand the philosophy and want to try a weird collection of ad-hockery instead.


I don't have access to powershell on linux but I think the syntax would be

(ls).Count

(where ls is an alias for http://ss64.com/ps/get-childitem.html which returns .net FileInfo objects, it can also return info for registry paths)

and

ps | ?{ $_.Name -eq 'tobekilled' } | %{ $_.Kill() }

(ps an alias for http://ss64.com/ps/get-process.html returns .net Process objects)

or the equivalent of pkill

Stop-Process -Name 'tobekilled'


> would unix be better if it were > cwd.files.count?

How about

    file:. count 
?


I agree with you to some degree. It's incredibly easy to write insecure software if it ever touches a shell.


I rather use objects and function composition in a REPL.

Kudos to Microsoft for bringing to Windows a little bit of Lisp Machine experience with Powershell.


I have used PowerShell, and currently learning Clojure. They never occurred to me as being similar - or did I miss the point?


Is a very subtle one.

Imagine having a workstation where the whole stack is written in Clojure (e.g. Lisp Machine).

Now when you open a REPL window, similar to what Common Lisp Interface Manager is, you can (:require) anything public from the OS, including applications, to interact with.

Powershell is similar in that, you are using objects and are able to reference any .NET class, COM instance or public functions from native DLLs by importing them.

So you can for example, import the Office COM automation API and interact with an Excel document that you just selected from the shell.


Office COM automation is what I did. I get what you mean, but in my experience, interfacing with native code is not always straightforward. Also there are odd cornercases where you need to fallback to p/invoke.

But More importantly, you can't change anything, you can only use it. So the FFI is nice and easy, but you could say the same about other languages. Or am I confusing things with Smalltalk images? Cl was somewhat before my time.


Exactly as you indicate, even in "classic" terminals we have features like unicode support, color, geometry reporting, mouse reporting, window title manipulation, arbitrary cursor movement, etc. All these are in widespread use today. These features could not have been implemented in a real tty, but nowadays I think it makes sense to have them. Maybe some are a little kludge-ish, but are we really arguing about their usefulness?

So why shouldn't we have a couple of extra escape sequences where the terminal could, e.g. draw an arbitrary bitmap? You are right, that would certainly require some sort of standard becoming prevalent, but why would a little extra capability (that doesn't break compatibility) be a bad thing?


Like extending email, there's a a chicken-and-egg problem. What terminal emulator is going to add a command that no program uses? What program is going to use a command that no terminal implements?

By all means implement this thing - I wouldn't be surprised if there were already terminals that did that. But personally I'd be surprised if it caught on. Compatibility matters.


In my post, I mention that iTerm supports inline images (although only in nightly builds so far). So does Terminology.

xterm actually support Sixel graphics now (although with 16 colors and a configure flag being set). Other terminals also support Sixel graphics, but not all terminal emulators and not the primary ones (Terminal.app, PuTTY, iTerm2, GNOME Terminal, etc).

Sixel and Regis graphics used to be available in actual terminals. I didn't mention Regis graphics in my post, nor did I mention Tektronix graphics, also available in vintage terminals. Both Sixel and Regis graphics were designed by DEC (Digital Equipment Corporation). Sixel was raster-based while Regis was vector-based.

Should we bother with Sixel today? Who knows? But there used to be standards for this sort of thing, but in the actual physical terminals, before we all switched to terminal emulators, most of which stuff with VT100 / VT220 emulation rather than anything too advanced. (Regis was available in the VT240, while Sixel came with the VT340, I think.)

Once the iTerm inline image support is out in an actual release, I have some tools that I'll update to support soon after.

But I have some follow up posts where I'll talk about some of this in-depth. This wasn't a random one-off post that I wrote. :)


"Exactly as you indicate, even in "classic" terminals we have features like unicode support, color, geometry reporting, mouse reporting, window title manipulation, arbitrary cursor movement, etc."

Is that true ? For instance, I am not aware that (for instance) the OSX terminal app does mouse reporting or geometry reporting.

Does default xterm ?


Yes. For instance, Vim necessarily knows how large the terminal it is in is. Vim also supports mouse input, allowing you to click around in different windows and whatnot.


In Terminal.app you can use the mouse to move the cursor at the command line. Since at least 10 years.


For a start I think it would be really awesome, if the terminal could display html (+css).


"For a start I think it would be really awesome, if the terminal could display html (+css)."

That's scary. My browser is a very complicated tool that does a lot of complicated things and has a huge attack surface.

OTOH, the terminal is incredibly simple and does almost nothing. That has been a very useful division of labor these past 20 years and I'd like to keep it that way.


This would probably be a good starting point. I've already found it quite useful sometimes to have programs output HTML+images so that the results can be viewed formatted. A terminal that could display that inline would be very handy! I don't really want one window for my text output and one for my HTML formatted output. There are some open questions (support links? do anything with javascript? etc.) but for my purposes just displaying reasonably-formatted graphical HTML output would be a useful improvement.

(Writing HTML files is workable, but a bit annoying to use in practice, because if you don't run the web browser from your program (= more windows) you have to tab over to the web browser and hit F5. And that assumes you're overwriting prior results on each new run, of course, which you might not want to do (= more coding and hassle).)

I suppose it wouldn't even have to be HTML necessarily, but HTML has the advantage of being some kind of standard and many people are familiar with it.


I wouldn't mind it.


I agree with you and disagree at the same time.

Command line interfaces are extremely powerful, simple to implement, extend and leverage, but, GUI's have their own advantages mainly in information density, context clues, and ease of operation. There is a world for them to both live in, but I would disagree with OP's approach of bring graphics to command line and suggest the approach of bringing command lines to GUIs.

I have already embedded a command line terminal in several GUI's I've built for industrial machines. The users can see the corresponding command line command pop up in the terminal when they click a GUI button and are free to type commands into the terminal. They can also define a script or batch of commands and easily assign it to a GUI button.

It was amazingly efficient for engineers to work with prototype machines whose functionality and controls were constantly in flux.

Downsides are that exposing a terminal to a potentially non-expert operator is a potentially dangerous, and I had to spend a good deal of time validating and sanitizing inputs(and risk missing something).

In the end, the terminal was removed in the production GUI, but was extremely helpful in the creation of a functional GUI that worked for the operator, rather than the opposite. In the case where the operator is always going to be an expert and is working with a complicated or constantly changing process, I could see a CLI/GUI interface working well.


It's also far easier to help someone over the phone/other "blind" medium of communication with a CLI than a GUI, as you can tell them to press keys on the keyboard and read back the output that shows up, instead of asking them to find and click on things - followed by their thousand-word response (a picture is worth...) describing in exquisite detail everything on the screen except for the exact information you wanted...

That's not to say CLIs are perfect for everything, because there are definitely use cases where a GUI makes sense.


Okay.

But sometimes, the logical output format for the response from a command is going to be an image. And sometimes, you'd like to view that inline with your commands in the terminal.

That isn't that radical a suggestion. And it doesn't turn anything into a big old GUI suddenly. :)


Clearly, the proper solution for this is pervasive hi-def videoconferencing. :)


I miss TermKit[1]. Its a real shame that the developer abandoned it after it got a lot of hype. There's a huge opportunity for someone to come along and make either a new terminal encoding which allows rich, interactive output or extend VT somehow to which allows the same. If you could extend the terminal protocol, you might even be able to get it to work over SSH.

HTML+JS seem like the obvious way to do it - even though the web is an awful platform, its standard, cross-platform and fully featured. Its the perfect worse-is-better solution for this.

I think the hardest part would be figuring out how to reconcile browser-like UI events and file streams. Maybe you'd need to make a standardized event serialization format so your process could receive serialized events via stdin or something like that. I think it'll be a really hard sell if we have to abandon our unix pipes entirely.

[1] https://github.com/unconed/TermKit

Previous hackernews discussion around termkit: https://news.ycombinator.com/item?id=2559734


> HTML+JS seem like the obvious way to do it > I think the hardest part would be figuring out how to reconcile browser-like UI events and file streams.

How about Chrome Apps? They've got a mix of file I/O capability and HTML/JS.


If I might plug a rich command shell I'm developing: http://pigshell.com (Source at https://github.com/pigshell/pigshell)

It provides

- A shell for the web. Runs in the browser, pure client-side.

- File-like abstraction for URLs and other entities exposed by web APIs

- Unix-like style of composing commands using pipes.

- Visualization using HTML

For instance, cp -r /gdrive/<username> /home will backup the contents of your Google Drive to your desktop (see http://pigshell.com/v/0.6.2/doc/gdrive.html for details). Replace /home with /dropbox/<username>, and the same command will back up GDrive to Dropbox. And so on.

While it is already useful, there is still some work, especially around hardening the file abstraction/APIs (and reams of documentation) before before it can be horizontally expanded to support a bunch more APIs and cloud stores. I am actively working on these and expect they'll take ~2 months.


Interesting. Why do you think that files are good abstraction for a web shell?


It's the old "if you have a hammer, everything looks like a nail". Since I'm a filesystem engineer, everything looks like a file :)

Seriously though: the file is a powerful and familiar abstraction. The primary motivation for pigshell was to provide a common minimum abstraction across different web APIs which would enable basic data movement and backup.

That said, pigshell commands actually pass objects across the pipeline; files are a kind of object. For instance,

  cat http://pigshell.com/sample/life-expectancy.html | table2js -e "tr" foo country data | head | printf
extracts data from an html table, converts them to plain Javascript objects and prints their json representation.


Are you familiar with Plan9? Everything is a file. Everything.


I will probably write a "More Rich Command Shells" to cover things I missed here that are important in some way (like Apple's MPW).

The next thing I want to write though is about building something that has a command shell UI today and thinking about how to do so in a flexible way that works with multiple output devices.


Thanks for that article.

I'm often thinking about how to present/"unify" these:

  - command (statements validated by some token),
  - repl (expression, less side-effect driven than the previous one), 
  - unary/immediate mode (each input event is interpretable right away, direct mapping between input and action), 
  - n-ary/non-immediate mode (some parsing occurs, gathering a few tokens into a higher level construct)
  - non keyboard based UI/UX (some sofware like Maya have proper separation, most mouse events have direct translation into object methods)


Please do - I liked this first article very much and would look forward to a follow-up.


Given all of that, and also Oberon -- '80s too, and even the Engelbart's Demo -- '68!, I totally every day wonder and can't understand why in 2010's all of the "modern" OSes still provide the developer just with text-only consoles??... okay, maybe for end-users there was a jump (in interfaces and features), and maybe it was significant indeed (movies editing, 3d modelling/sculpting, possibility of instant communication with significant fraction of all the people in the world, to bring up some). But it still feels like even for them, some things were there, and now are not (sorry for vagueness, but I don't have much time now to think about examples, unfortunately. When I'm gonna finally start this blog thing, one day...).

Any theories, anyone? I'm really curious. Still believe this can be improved, and work on some ideas in my free time, but I often wonder why I have to, and I can't already use those beautiful ancient features?


That's a very interesting question.

I'd guess that the technical decisions that differentiated early unix from the lisp machines etc. were based on hardware and cost limitations.(the development of unix is something I'd be interested in reading more about) Then as unix took off, these technologies became entrenched, with a kind of apologetics developing amongst users who liked those systems, or never used anything else.

There's an interview with Bill Joy where he said that Vi's famous modal interface was merely a result of his poor quality terminal and network connection, and now it's used by millions of programmers. I'm not saying that these users are wrong about the benefits of modal editing or the unix text interface etc, but that these are discovered benefits that are then used to retroactively construct a containing narrative of justification that often walls people off from alternatives.

I'd also hazard a guess that many of these technologies were simply inaccessible and/or unknown to the mass of post-pc-revolution developers who create the bulk of our present systems. The number of devs who had access to Lisp machines was small compared to the number who came in with Unix with its success in the workstation market, and tiny compared to the number of devs who came in through home computers/PCs.

I myself grew up with 80s home computers, moving to the PC and Linux in the late 90's. Lisp machines, Oberon etc. were unknown to me until a few years ago, and information about them is still hard to come by. Nearly all the lisp machine sites are web 1.0 with broken links etc. Very few of them try to market the benefits of these systems to people in the wider community.

After I got interested in lisp and lisp machines (thanks pg!) I spent a weekend getting that notorious leaked Symbolics Genera distribution working on Linux, inside virtual box on my mac. After a few hours in the Listener, with its rich output and superior incremental help system I wanted to show it to everybody I knew. It was one of the most incredible things I had ever seen on a computer. For the next few weeks at work I was occupied with the constant thought, "This is not as good as Genera". It's had a huge impact on how I think about software, even my indie game development.



Hm, that's a really interesting theory, and the stories and related arguments too, thanks a lot! I didn't think of it before.

In fact, I started hearing of all of those OSes fairly recently too, but I still see myself as a "youngster" in programming world, and thus I thought those technologies were more well known at that time. Also, that they were more well known to Important Figures and Big Companies then, so they could try to build on those ideas.

But now I start to recall, that most of those OSes are usually reported to be used and deployed quite rarely (Lisp Machines e.g. often dismissed because of high price and hardware requirements), so that could have limited their exposure. And also, I'm ashamed to admit I forgot about this (oh the times!), it must be taken into account that there was no Internet at the time, so this also made sharing of ideas harder than now...


>the development of unix is something I'd be interested in reading more about

http://www.levenez.com/unix/ has a good amount of info and links on the history of Unix and the people who worked on it. I came across the site a while ago and browsed it some. Interesting stuff, some of it at least. Recursively traversing the links should give even more.


For me, because I can't compose strings of gui clicks into an ad hoc list of transformations on text. And I do that a lot in the shell.

There is also no command history for my gui clicks; once you've clicked on something, there's no way to reuse that click in some slightly different way.


In CLIM, a graphical presentation is only a representation of an underlying type. Types will have default representation (e.g., basic text like you would get from printf), but you can also override this using with-output-as-presentation (see p. IV-1.30 of [1]).

So, when outputting a number, you could display it in the output stream as a circle of radius N. Then, any input which wanted a number as argument (using "(accept 'integer ..)") would let you type a number or click on that circle.

This could be extended to shell command parser for richer input choices (rmdir can only accept directories, cat won't). Existing utilities could support a "richly typed stream of objects" (graphical ls) or a wrapper or output processor could add it. The latter has the advantage that not all commands would need to be aware, and it could be multi-functional (could work on "ls|grep", "find", "tar tf" output--but you might need to specify type hints).

I think it would be handy to have all my recent files, directories, outputs handy in a list on the side (with keyboard shortcuts too; I'm not a clicker..).

So in no way should your command history have to be compromised just because you have alternative input methods available.

[1] A Guided Tour of the Common Lisp Interface Manager, http://3e8.org/pub/scheme/doc/lisp-pointers/v4i1/p17-rao.pdf


well, not at that minute level, but every application worth its name has an undo log - and that's a pretty close functional equivalent, IMO.

And: applications that have Macro recorder features (Office and many text editors) allow you to actually record your actions - clicks or otherwise - into code that can be rerun.


The problem there is that every application needs to implement a macro recorder, and every application needs to implement history and undo. With small programs that all handle text the shell takes care of history and automation, while the other programs can focus on solving a new problem.

Why have macros and history reimplemented badly by every application when one application could do it well?


True, such a feature should really be system-wide - something like OSX's Automator, maybe.

That doesnt take away from the point, however, that GUI actions can be stored in history, composed, etc.


But right now, they aren't. :)


Hah, but here we come back to my question: which was specifically not about what we do have "right now", but why those things that we do have right now are worse than the things "we" had before??


It's perfectly possible for a GUI to have a command history, if the GUI is just a front end to a CLI. Then you can click around when you want to explore, and can go to over to the CLI when you know what you want to do and want to establish a more streamlined workflow. Or even click around and do stuff, and then extract a script from that recent history of clicks and interactions.

Some R (programming language) GUI frontend does it in this way.


Not sure why, but I'm reminded of the old WordPerfect dual mode, with rendered text on top and raw mode on the bottom. It was a little annoying because sometimes that was the only way to get something done, but it was also fairly powerful.

It would be kind of cool to have gui interfaces (including the general desktop gui) have something like this dual mode.


Some CAD programs do this. You could execute a command with fully defined parameters to make something happen, or maybe you'd execute the command and enter the parameters by selecting things in the GUI when prompted. It is a very powerful way to work, but the learning curve is often steep.


Because many seem to be willing to go back to the 70's (vi/sh) instead of embracing the progress you mention.

Since I discovered UNIX, with Xenix in 1994 followed by many other variants, I always looked for ways to replicate such workflows in UNIX.

At the end of the day, Mac OS X and Windows communities are more welcoming to such ways of working.


> Because many seem to be willing to go back to the 70's (vi/sh) instead of embracing the progress you mention.

Just because it's old, doesn't mean it's only about nostalgia.

Besides, I for one can't have this kind of nostalgia because in the '70, my fingers were a bit too short.

There is something extremely convenient to be able to use the same environment everywhere, with minimum prerequisites, because terminal emulation software is very common (probably as common as Web browsers).

I also find it more natural to deal with the system with a CLI when you spend your time editing source code or doing sysadmin stuff; it doesn't break the flow. Of course it's totally different if you're a graphic artist or a Web developer.

Sometimes CLI makes more sense, sometimes GUI makes more sense. But accusing people of being stuck in the past, that makes no sense.


Except REPLs are CLIs on steroids.

UNIX shells can only seem powerful for those that never had the luxury of playing with Smalltalk, Lisp, Mesa/Cedar or Oberon environments.

Where you have a CLI and GUI experiences interact together to create a composable workflow experience.

Where I can do function composition on my REPL over data that I just selected with my mouse on a word processor, just to give a possible example.

Where public functions from dynamic modules are exposed on the REPL and can take part in any set of commands.

There is this primitive notion that a CLI needs to be the UNIX way, when a REPL as CLI is so much more powerful.


IPython already makes for a pretty good bash/zsh/etc replacement for many things. You can get a GUI using the IPython notebooks as well. While I haven't made the switch completely yet, I always keep an IPython session around in an extra tab, since it is very often just much simpler to do something there than in bash.


>I always keep an IPython session around in an extra tab

By "tab" you mean tab in your web browser; do you not? (I ask because there are non-web-based IPython thingies.)


I actually meant a terminal tab (I'm using Tilda as terminal emulator). I'm only really using the web-based notebook interface when I need to display graphics for something.


I am very glad I asked :)


But, again, why? this can still have many reasons: not willing because of technological obstacles? complexity? because they shown in fact to be somehow worse? (e.g. pure text easier to read, mold, and more universal?) because of some social obstacles? (if yes, of what kind?) what else could that be? (those are just a few of my random quick theories, have I described all possibilities?)

edit: the comment by zorbo seems an interesting answer to my question, but I'm still not 100% convinced; also, I must still ask how can we be sure we're not victims of a text-mode "Stockholm Syndrome" in this regard?


Because the majority of those people never had the opportunity to work with Smalltalk, Lisp Machines, Oberon, Amiga,...

So they look around and see only UNIX CLI.

It is just like mankind during the middle ages that never experienced how the Roman and Greek society were developed before the empire downfall.


Strange he didn't mention Xiki: http://xsh.org/ http://xiki.org/


If you found this interesting, you may also like GCLI (as featured in the Firefox dev tools command line - or you can play with it here: http://mozilla.github.io/gcli/ ).


GCLI is interesting, but I didn't mention it because I feel like it focuses more on the issue of command parsing / completion.

That said, that's a great topic to cover! I think GCLI does a pretty good job of command completion. The Lisp Machine did as well. I have friends who love some of the router CLIs, but not sure which one(s).


Cisco's IOS is an example.


If you come to Freiheit.com next week (16. Oct 2014) to the Clojure User Group Meeting in Hamburg/Germany, I'll demo the Dynamic Windows user interface of a real Symbolics Lisp Machine. Including its command shell called 'Dynamic Lisp Listener'.

http://www.meetup.com/ClojureUserGroupHH/events/207314372/


Cool! Do you know if the demo will be recorded?


This demo appears to be running on an emulator instead of an actual antique piece of hardware but you can get the idea.

https://www.youtube.com/watch?v=o4-YnLpLgtk

the AI winter is something you don't hear too much about. http://en.wikipedia.org/wiki/AI_winter


It won't.


Oh the sadness. Please harass someone with a capable smartphone to attempt at least :)


Slightly off-topic, but the recent surge in responsive UI had me thinking thus: If we are now driven to merge UI logic across different graphical devices, can we think of apps that span both textual and graphical devices?

After all, the core functionality of the application remains the same. To use a simple example: when you search for a product online, get a search result list and then select one from the list, couldnt this flow be modeled just the same in both gui and text interfaces?

I'm thinking back to the turbo-pascal style applications of the past that produced full-blown IDEs in text, or the wordstars/wordperfects of yore: the UI model that sits behind those apps cannot be much different in principle from the modern day equivalents.

Even farther back, there was a time (and probably still is for college assignments) when cli applications had a prompt-read user input-respond cycle, replete with text-based choices to select from and so forth.

What if we were to merge the two worlds instead of trying to get one to confirm to the other?


And this is why UNIX shells feel so primitive.


What about the Aurora/Eve thing? https://www.youtube.com/watch?v=L6iUm_Cqx2s

It is a shell, isn't it?


How about a declarative and idempotent shell? Well, more declarative and idempotent than bash + the GNU core utils.


How would this be useful?


This comment thread discusses the methodology. https://news.ycombinator.com/item?id=7378764#up_7380392


CLOS and CLIM always sounded to me like the names of programs you'd expect to see competing at disc wars, or racing in a lightcycle grid.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: