177 comments

[ 2.9 ms ] story [ 193 ms ] thread
Very interesting project, already using it!
You can use `man test` for [ ] which it currently reports no man page for.
Very well done. Now I just wish this was a shell program!

  user@server:~$ explain iptables -A INPUT -i eth0 -s ip-to-block -j DROP
This is a great idea!
I'll donate $100 if the author wants to build this and open source it. [Ed: As a shell application locally]

A new "explain" command could help me, my team, and save us an enormous amount of time getting up to speed on some of our org's long-term system maintenance scripts.

How about an API where you can POST your script with curl -X and a unique link is returned that explains the script when you hit it with a browser?

#shutupandtakemymoney (DevOps is fun, teaching not always)

(comment deleted)
I would never install this in this format. I'm not going to POST my bash history!

I'd prefer a model where you download a definition file (if it needs to be "updated" at the start frequently)

Thanks for the incentive, but it's not needed and if I do get around to it, it'll of course be open source.

The main difficulty I had with writing a command line utility is figuring out the UI in a console. Suggestions are welcome of course.

Also, there are two possibilities for a client: the first queries an API on explainshell.com by sending it a command line. This has the advantage of the client being thin, and using the centralized man page database which is probably more accurate. But this means that you're potentially not explaining the exact command you're running locally, which may be confusing.

The second option is to run the man page parser, matcher, etc. locally against the man page on your machine.

One advantage of a local repository is that it is more likely to match the software versions on the local machine.

However, perhaps the best thing would be to allow both local and remote queries :-)

You can run the web server locally. See the source code readme:

https://github.com/idank/explainshell

It should be trivial to whip something up that will generate the right URL for a set of arguments, running either on your local web server or against explainshell.com

I thought of quickly writing one, but it doesn't have an API. Something like this would work well:

POST your query, e.g.: tar zcf - some-dir | ssh some-server "cd /; tar xvzf -"

Returns:

    [
        ["tar(1)": "explanatory text"],
        ["z": "explanatory text"],
        ["x": "explanatory text"],
        ["f file": "explanatory text"],
    ]
etc.
I had something similar in mind. But this format means that repeated arguments that aren't adjacent will have their help text repeated.

Feel free to open a bug and we can discuss the options there.

Um... the output wouldn't be interesting for that iptables command -- it's simply a single program with arguments; no shell syntax involved.

I suspect what you really want is an iptables demuddler tool that explains the insane "chains" metaphor and explains how individual packets are going to behave. I'd like that too, but it's not this tool.

If all it did was parse program arguments and display usage info it would be super useful. Bash syntax is mostly trivial while there are thousands of arguments across hundreds of programs.

    #!/usr/bin/env python
    
    import sys
    import urllib
    import webbrowser
    
    url = "http://explainshell.com/explain?cmd=" + urllib.quote(' '.join(sys.argv[1:]))
    webbrowser.open_new(url)
(webrowser.open_new doesn't seem to be always working for me, not sure why, I've never used it before)
(comment deleted)
At least you didn't try to do that in bash! ;)

One suggestion though: If there are no command line parameters, then read a line from stdin, so you don't have to play the game of trying to properly escape all of your punctuation in the command line to get it into sys.argv[1:] without any corruption, and can just copy and paste it into stdin.

Hmm, that raises the question of what should happen if you pipe an entire shell script into it, like "./configure"? That might be considered a denial of service attack on explainshell.com.

I've definitely written a URL escaping routine in bash before :)
See https://github.com/jeroenjanssens/data-science-toolbox/blob/... for a bash script that interfaces with explainshell.com.

I wrote this script a while ago. I just needed to update the request because the API had changed a bit since then. Please note that it depends on the scrape tool in the same repository, which in turn depends on the python packages lxml and cssselect. But once you have that set up, you can explain commands from the shell! :-)

Sounds like a job for a little statically compiled Go program :-)
The trouble with that approach is that you have to escape special characters:

$ explain cat filename | sort # won't work

$ explain 'cat filename | sort' # presumably would work

I wonder if the best approach is to make `explain` behave like a prompt. If there was some way it could inherit bash's command history, even better

$ explain

explain> cat filename | sort

Gorgeous. Amazing. Absolutely fantastic. Easy the coolest and most useful thing I've seen on hacker news in a while.

Enough gushing, now some bug reports:

"read -r random_line < <(sort -R file)" yields "syntax: expecting filename or fd (position 22)"

"nc HOST PORT | tee movie.mp4 | mplayer -" I can hover over movie.mp4, but I can't scroll down the see the description without losing the emphasis on that path. I'd suggest letting the user click on the portion, or perhaps a long-hover effect?

The first bug is acknowledged in the page: "support for (...) command substitutions will be added later on"
> I can hover over movie.mp4, but I can't scroll down the see the description without losing the emphasis on that path. I'd suggest letting the user click on the portion, or perhaps a long-hover effect?

What if the command was simply pinned to the top of the screen as you scroll down? This would require some trickiness to make the atoms remain connected to their documentation as the documentation slides under the command, but would allow you to view any documentation on the same screen as the command itself.

EDIT: On the other hand, I just noticed that there are buttons to only show the documentation for specific subcommands, so you can always use those to cycle until the documentation you want to see is visible.

The wiring is sexy, but this is a textbook cases where tabbed panes would be perfect: just have each command segment be a tab, and the corresponding docs be in a pane underneath.
(I have no relationship with OP or the submitter/submission).

>Gorgeous. Amazing. Absolutely fantastic. Easy the coolest and most useful thing I've seen on hacker news in a while.

>Enough gushing, now some bug reports:

I like the way you wrote your comment! It could stand as an example to everyone. Yours might have had enough gushing, but I think every "negative" comment should start with as high praise as it can muster.

If the whole thing isn't as good, then it should first be "damned with faint praise" and then specific constructive criticisms shown. Obviously the praise doesn't have to be as strong as your comment.

I just want to point out how awesome a comment like yours is - it is incredibly hard to put together and share something. We could all do well to remember that when we point out how to improve it.

Thanks, that's really fun to hear.

ACK on the command substitution not working, with the current lexer that I have in place fixing this isn't easy and might take a while. But it's definitely up there on my todos.

Yeah, long pipelines are somewhat of a problem. You can currently navigate the commands with the buttons at the top, maybe they're not visible enough.

But I like the idea of being able to pin a particular line by pressing it, but I fear it might be a bit subtle and easy to miss.

I liked one idea submitted: having the command pin to the top of the screen on scroll down. It would be tricky to make happen with the hover effect for the boxes, though.
Yes, I had this suggested on numerous occasions and gave it a go a while ago and it's indeed not trivial.

If a JS wiz would like to hack on this I'll gladly help and accept it.

Do you have any thoughts, or writings that you could point me to, regarding shell's parseability? For example, is it possible to parse a shell script without running it? Would it be possible to extract Bash's lexer+parser into a stand-alone library to be used by IDEs?
Yes, you can parse without executing. I think shell is easier to parse than it seems, there are definitely some nuances that might be tricky to emulate, but I guess it's a matter of effort and how far you're willing to go. For syntax highlighting in IDEs, you probably don't need much, and maybe even a few regexs can get you close enough.

I actually spent a considerable amount of time going over bash's parser [0], and also zsh's [1]. Bash uses lex/yacc with some custom code. zsh seems to have a custom written lexer/parser.

Unfortunately none of them were written to be used as a library, as evident by global state, and a lot of hooks for prompts while parsing, etc. It might be possible to somehow make it work, but it seems like a lot of work to me. You might have an easier time looking at the parser I wrote, and extending that, or rewriting it in another language (as it's fairly small compared to the ones you find in shells). There's also libbash [2], haven't looked closely though.

[0]: http://git.savannah.gnu.org/cgit/bash.git/tree/parse.y

[1]: https://github.com/zsh-users/zsh/blob/master/Src/parse.c

[2]: http://www.gentoo.org/proj/en/libbash/

Yeah, the buttons are not visible enough IMO. I didn't even notice them (nor connect them to the output) until you mentioned it. Also, maybe hook them up to the arrow keys on the keyboard? Same problem with scrolling for large lists.
This is amazing! It's great for someone like me who, while knowing their way around the shell, isn't as well versed as some of my more veteran co-workers. While it's great to hear explanations of some of the more dense lines they give me to run, that's not always possible and can be a bit annoying. This could help take some of the pressure off of them to drag me through. :P
This is pretty cool but what I found annoying was matching the snippet of code and the description together. Take this for example: http://explainshell.com/explain?cmd=true+%26%26+%7B+echo+suc...

The command is: true && { echo success; } || { echo failed; }

But the top box description is for echo parameters. The next one is for echo. Why can't it go from top to bottom in order of the command? EG: Start with true, then &&, then {, then echo, etc.

The way it is, I spend a lot of mental energy matching things up.

I agree it's a little counter-intuitive. But if it's top to bottom then all the lines would cross each other which would ruin the UI. If there's a way to make it top to bottom while keeping the UI useful, I'd love to hear!
Maybe I'm missing some point, but I don't think you need the lines if it goes top to bottom. Or, maybe you'd only need one line to show up if you highlighted a snippet/description: To point back to what you're hovering over.
I think it'll be hard to match portions of the command to their boxes if there were no lines at all. How would you know that the `v` in `tar xzvf foo` matches the 4th box?

Having a single line when you hover could help, but sounds confusing for new users that are unaware of this feature.

That's a fair point. What if you put the snippet and the description side by side so you don't even need the arrows? Perhaps like this:

  tar description1
  x   description2
  z   description3
  ...
> If there's a way to make it top to bottom while keeping the UI useful, I'd love to hear!

I understand that the UI looks very nice, but at least for me, having the explanation boxes be in order would make it a lot easier to use. So here is my suggestion:

You can keep everything looking exactly like it is now, except get rid of the lines altogether, and display all of the explanation boxes in order.

When the user scrolls down far enough, display the query at the top of the page with fixed position so that it is always on screen. Then topmost displayed explanation box will get highlighted, along with the relevant portion of the query; unless the mouse is hovering over a certain box or portion of the query, in which case that command/box pair becomes highlighted instead.

If a user tries to scroll with the mouse wheel or keyboard, but there is no more content to display on the page, then the scrolling causes the highlighted box to change instead.

If a portion of the query is highlighted which is not on the page, then clicking that portion will cause the page the jump so that the corresponding box appears and becomes highlighted.

I know I'll be lynched for suggesting an extraneous JavaScript library like Bootstrap here on HN, but what if the command stayed visible at the top of the screen once you scrolled past it on the page (just like how Bootstrap's Affix plugin works) and the relevant part of the command you were reading about became highlighted as you scroll down the description (just like Bootstrap's ScrollSpy plugin).

That would be an intuitive UI without relying on wires to connect the content to the sections of the command and it lends itself to responsive layout as well because the command can easily wrap to multiple lines without losing clarity as you read the explanation (where the wires might start to eat into screen real estate at phone width and become much less clear if the command had to be split to multiple lines to stay visible)

Holy moly, this might be one of the best things I've seen on HN in a long time.
I don't know what I was expecting, but one of my most-used command lines, "du -a | grep foo" is pretty uninformative.
Tried it. The explain read-out seemed reasonable. Care to elaborate how it wasn't informative?
The explanation for "du" and its -a flag make it sound like I'm trying to find out how much disk space my files are using. Fine, that's the usual usage, but the point here is that it lists out every file under the current directory.

The bigger problem is grep. We're told that grep prints lines matching a pattern, great. But then the explanation of the arguments makes it sound, to the uninitiated, like I'm giving "foo" as the filename, because the site doesn't include the actual grep syntax.

It doesn't really explain what the command line is doing. It does seem to do a decent job of telling someone who's already fluent in shell usage the specific meaning of all options given. That's actually pretty important these days where any given GNU util will have flags for every single letter of the alphabet in both upper and lower case.

That's not really solvable in this case, though. All explainshell has are the man pages of the commands. It cannot know how they will interact with each other. It should be at least semi-possible in PowerShell (because you have output type information and parameter type information), but I hit a roadblock with ExplainPS a while ago and haven't had the time to resurrect it.
Perhaps you should go for find . / -name filename instead. Using du -a | grep filename works for sure, but it a bit of hack.
If you're just trying to locate a file in the current directory, you should probably be using find.
Just for definiteness, the equivalent "find" idiom would be:

  % find . -path '*foo*'
You need -path, not just -name, to match the whole name as du does.
I'll point out that the find command is 21 characters, while mine is only 17. Efficiency!
Yes, you have a point (plus, those stars, they burn the eyes).

But, your detractors will say yours is two processes and theirs is one. Efficiency!

The kernel could start 100 processes in the time it takes me to type those extra four characters. We won't run out of processes. I did a test, finding .txt files in /usr/share, it took about .25 seconds longer with du and grep, which seems like less than it takes to type 4 more characters.
How long does it take you to type a character???
Assume I type 80 wpm

A word is standardized as 5 keystrokes

80 wpm is therefore 400 keystrokes per minute.

Divide by 60 to get about 6.6 keystrokes per second, or about 0.15 seconds per keystroke.

Therefore it would take about 0.6 seconds to type the four extra characters, giving a net savings to use du+grep instead.

And 80 wpm is probably a rather fast estimate; I'd guess that I type slower when I'm writing commands than when I'm entering English text.

I will switch immediately! ;-)
This is all moot, because you can just alias either command to a single letter if you use it that much.
I must've read it wrong, or you fixed it, 'cause I read it as 25 seconds, hence my question! :)
I remain convinced that "find" also contains a text editor and a Pacman game, but I've never cared enough to read the damn enormous man page. Also, not every system has "find", but everything I've used has "du" and "grep".
I think I can one-up you.

  (while :; do cat ; sleep 2 ; done) <file
I'm curious why this is one of your most-used commands. If you want to know the sizes of all files matching 'foo', this is a horribly inefficient way of going about it.
"grep searches the named input FILEs (or standard input if no files are named..." Important bit being "or standard input."

Also, what an odd one-liner. What's the use case for this that makes it such a common command: file names and sizes for all files matching a pattern beneath the current subdirectory (and all subdirectories and files within subdirectories matching that same pattern)? Genuinely curious.

Nice. Very nice.
I give out this link to all my developers that are just getting a feel for the terminal. Thanks so much for this!

A nice to have: Having the command that was originally entered follow you down at the top of the window so when I'm looking at a long piped command, it makes it easier to follow

Really cool project! I can already see myself using this a lot.
Very cool! It would be great if you would provide common usages for a given command if the user didn't provide any switches. That could be links like the ones you have in the "examples" section on the landing page.
The UI with the svg "wiring" is awesome. You should consider abstracting away that functionality so that it can be reused by other projects.

Right now I'm imagining explainphys ;) where each term in a physics equation is explained e.g. The magnetic force felt by a particle of charge q moving with velocity \vec{v} in a magnetic field \vec{B} is

      \vec{F}_B =   q \vec{v} × \vec{B}
       |            |   |     |   |______magnetic field    
    magnetic force  |   |     |
                    |   |   cross
               charge   |   prod.
                        |
                   velocity of particle
This is beautiful! It will come in handy for filling in the vast holes in my knowledge. I think it would also make a great resource for those just starting to work with shell. Very well done indeed!
So I fed it : cat ./trunk/.config |awk ' /CONFIG_TARGET_BOARD/ { gsub(/\"/,""); split($0,a,"="); print a[2] }'

A little one-liner I worked up a few days ago to quickly show me which architecture my OpenWRT trunk was last built with. I'd really like it to explain in much more detail what each of the terms inside the awk command do. Perhaps make "explain" modular so that people can add more detail to the gazillion things that can happen inside awks, seds, greps, etc?

Fabulous idea. This should have been in unix all along as part of the man system.

That'd be brilliant.

We should have a `wtf?` command, used like so:

  wtf? yes | sudo apt-get install libpq-dev
Results would be ncurses, top line of screen is command with current subcommand highlighted, and rest of screen is less'ed explanation.
It's definitely doable to add dedicated parsers for options of awk, sed, et al. But it's a lot of work... I doubt someone will go through the trouble of writing a parser for awk, just for this..

What is possible and quite easy is creating links for things that are explained in other tools, such as linking the regex argument of grep to some site that explains regular expressions, or somehow integrate it into the existing UI.

This is fantastic. Even with simple examples like `ls -la` it shows the documentation and other flag synonyms for all of the passed flags. Very impressed.
I started learning Shell last week. This couldn't have been better timed :)
:(){ :|:& };: or GTFO :)
I tried that as well. It says "Missing man page" :(
Doesn't seem to support backquotes? For example

    for x in `ls ~/foo`; do echo $x; done
doesn't yield anything remotely interesting.
New style subshells aren't supported (yet) either:

   for x in $(ls ~/foo); do echo $x; done
You know you're on the right track when people are saying, "But why isn't this in there already?"
This is quite impressive.

I'd love to see the argument explanations narrow down sub-arguments. For instance, "find -type f" ought to just show the top-level description for -type and the description for 'f', not all the other type characters.