

Huffshell: You probably type too much. - socmoth
http://paulmckellar.com/huffshell/

======
dredmorbius
While I'm not sold on this particular concept, it does highlight a feature of
modern Unices which bears pointing out: the command-line environment isn't
some dreadful primitive thing that should only be relied on as a last resort.

Rather, it's the evolutionary end-point of some 40+ years of continuous
improvement in issuing and processing text-based information streams (both
commands and outputs), in a very powerful, highly flexible, extremely
adaptable manner.

The age of "Oh, Linux, that's like DOS" are far beyond us. But it bears
pointing out that this is much like comparing a pogo stick to an F-22 / Boeing
777 / Mercedes E-class. Yeah, the both get you places. How, how much, at what
speed, and in what style ... differ.

~~~
dllthomas
>But it bears pointing out that this is much like comparing a pogo stick to an
F-22 / Boeing 777 / Mercedes E-class.

Well, more like comparing an early horse drawn carriage to the latter three. A
pogo stick has always been a toy - never designed to get work done, however
inefficiently. Primitive command lines were still attempts at letting you get
work done, they just weren't as good as what we have now (or, in some cases
and for some purposes, contemporary graphical alternatives).

~~~
dredmorbius
It's also worth pointing out that many current CLIs are still grossly
crippled. The DOS / CMD.exe environment in Windows. Oracle's sql client.
Sun/Oracle's default tcsh. Cisco's IOS. All of which lack one or more of
readline, tab completion, command history, pipelines, and other, really basic,
modern shell features.

One of the first selling points for Linux when I first started exploring it a
decade and a half ago was that while some of the internals were a tad crufty,
the _userland_ (much of it, admittedly, GNU) _didn't_ suck, and _didn't_ suck
in a much bigger way than stock commercial proprietary unices _did_ suck.

Pogo stick or oxcart, the point is that many such tools were, or are now,
pretty much intentionally crippled.

~~~
cutie
DOS supported those you mention, and cmd.exe finally has them on by default in
recent winders. It is still primitive though in everything else, e.g.
scripting. Powershell with its weird syntax is a big improvment, but we split
up after XP.

~~~
dredmorbius
I haven't used Powershell at all. Would've been far better for MSFT to have
adopted bash and provided windows-specific utilities where absolutely
necessary.

DOS / cmd.exe, last I checked, didn't have true pipes, true shell expansion,
or true readline capabilities (unless it's now GPLd, which I very much doubt).
It does have some history and tab completion (though that last works weirdly
IMO).

By shell expansion: expansion of wildcard globs by the shell, and not by
specific utilities. Piping -- I forget the specifics, but it's always seemed
hit or miss, mostly miss. Readline: see readline(3).

~~~
cutie
Yep, NIH.

DOS was primitive but the things you mentioned worked, even if they were a
simulation. The end user was unaware, unless they needed real OS capabilites.
In which case, why were they using DOS?

Cmd has a lot of improvements most people are not aware of because they were
off by default. Still they refused to do further improvement necessary to make
it very useful. There is a 3rd party shell called 4NT that is/was a compatible
and very powerful replacement.

~~~
dredmorbius
The thing about DOS's globbing is that it wasn't DOS that was doing the
globbing, but executables. And they'd do it inconsistently. The executables
were also _aware_ if they were passed, say, a '*', and might change their
behavior as a consequence (I'm trying to remember whether or not this was
actually been the case, can't say, it's been too many years).

Which doesn't happen in any Bourne-compliant shell, as it's the shell which
expands the wildcard, not the app (an unexpanded or escaped wildcard character
can of course be passed to an executable).

~~~
cutie
True. I remember someone here complaining about that just the other day, said
it was a bad idea, but I can't remember why. I prefer the shell doing it.

------
jerf
I've actually been thinking about how I'd like this for all my typing, but
it's difficult to imagine how to do it.

One trick I've learned, if you want to make sure you get the benefit of this
sort of approach, is to ensure that the new alias is not just possible, but
mandatory. If you map "git commit" to something, you should make it no longer
possible to type "git commit" instead of your new alias, and doing so should
pop up the correction. This can also be used to move keys around; turn your
Caps Lock into _a_ Control key, you'll never use it, but if you unmap the left
Control key at the same time, you'll find you've adjusted in about 5
uncomfortable minutes. It's fast enough to be worth experimenting with.

~~~
tikhonj
I've certainly found this the case when creating new key bindings for Emacs.
Of course, this now means that other people have a little bit of trouble using
my Emacs because some of the basic key bindings don't work any more and some
of them do something new :).

I'm now using this strategy whenever I want to change something like a common
command or key binding--essentially anything that is a habit I don't have to
think about.

Another thing to note is that it really helps if you come up with the alias or
new key combination yourself. I find it takes almost no effort to memorize a
key binding I choose myself as opposed to remembering a new one that comes
with the tool itself.

~~~
sciurus
For vim I benefitted greatly from

    
    
      " disable arrow keys
      nnoremap <Up> <nop>
      nnoremap <Down> <nop>
      nnoremap <Left> <nop>
     nnoremap <Right> <nop>

~~~
tikhonj
Yeah, that's the advice I'd give to people starting out in Emacs too. I didn't
use it but somehow got the hang of navigating around with the keyboard anyhow.
It's probably because I personally did not use the arrow keys before switching
to Emacs--I usually used the mouse.

A bunch of people I know do use the arrow keys to move around, and it's quite
a loss. You don't gain _that_ much just by being on the home row, of course,
but there is _some_ gain. However, the real win comes when you start using
higher-level movement commands and moving by
word/line/paragraph/expression/whatever. People used to the arrow keys will
not be able to take advantage of these nice commands nearly as easily.

------
dllthomas
Hmm. I think my history is a very poor measure of the typing I do. It's the
rare command I type that doesn't benefit substantially from tab completion
and/or modification of earlier commands.

~~~
riffraff
came here to write this. For example, if I look at my history, I have a bunch
of `git diff` and `bundle exec rake test`, which actually correspond to
`<C-r>-d-i` and `<C-r>b`, and a few `heroku ...`which amount to `he<Up>`.

The single command to actually count this occurrences required way more
typing.

------
com2kid
If you have to do it once, fine. Some work needs to be done.

If you have to do it twice, think it over a bit.

If you have to do it a third time, automate it.

I am lazy enough that I have aliases setup to change to directories I
frequently use. I know people who have gone far beyond anything I have done
and looking over their shoulder when they are at the shell will show a highly
custom environment with dozens of custom scripts that automate all sorts of
multi-step commands.

I even know a few people who have used most of the alphabet to create single
letter scripts. That is efficient!

~~~
secoif
Aliases to cd into directories? You need to check out autojump style tools!
Will change your life.

e.g. <https://github.com/rupa/z>

I very, very rarely type cd by hand anymore, mostly just use z and popd

------
B-Con
I fail to see why this is "too much". Pragmatically, for a competent typist,
all of these duplicate commands add up to a grand total of what, like 2
minutes a month? You will easily spend a few months of savings performing the
analysis and crafting the aliases.

Not that I'm against aliases - even minor time savers are indeed worth it - I
just wouldn't call it "too much". I bet that a lot of people wouldn't care
that much.

~~~
wccrawford
I agree. You need to look at that net time saved, not the gross.

In addition, if you're at a terminal on a new server, or someone else's
station, all those aliases will be gone.

For me, that means any special aliases or scripts had better be awesome enough
to convince someone else to use them... Or infrequent enough that I can't be
bothered to remember the whole command. Or just so useful that it's worth
overriding the above.

Shortening a 3-letter command into a 1-letter command is not going to fit into
the above. Especially when I will have typed 'git' before I remember that I
can just type 'g' instead, since I touch-type without looking. It just flows
out.

------
X-Istence
The biggest issue I've had when attempting to customise my shell is the same
issue I've had while working with my custom vim setup and that is the issue of
a different machine.

When I log into a new machine I still need to be able to find my way around, I
still need to be able to edit files, I still need to be able to run various
different commands. These can even be completely different shells or different
versions of vi (nvi on FBSD for example, vim without python support on another
system and so on).

Yes, my workstation has my vim customisations, but it only has the bare needed
ones the rest are stock. Even on a vim without any of the scripts I have I
would be proficient and I wouldn't miss a beat. Same thing for the shell,
typing commands in full means I don't have to worry about muscle memory.

ll for example for ls -la is nice and all, but it isn't available on most of
the machines I administer so I end up typing out ls -la anyway. That has
become muscle memory for me now, and I am not worried about trying to change
that.

------
rocky1138
Does this include the times where the user presses the 'Up' arrow key to
retype a previous command?

I think that would skew the results a bit if so.

~~~
natep
I'll often use Up/^p/^r(i-reverse-search) to find a previous command and edit
it's argument, which is where the tree nature of this tool would come in
handy. If I 'type' the first n terms of a command enough times, it might be
better to alias that part of the command rather than navigate my history and
then edit the rest of the command repeatedly.

------
AlexCP
I find that using good aliases for common git command is quite useful. Here
are my gitconfig to show some examples.
<https://github.com/alexcp/gitconfig/blob/master/.gitconfig>

------
robertduncan
Using git commit -m is a guaranteed way to write useless and ill-formatted
commit messages.

~~~
zheng
Unless of course you only need to write one line. Not every use of git
requires complex formatting in commit messages. Almost all of my git repos are
used by me alone, and one line is enough. Obviously this isn't the main
purpose of git, but I'm guessing I'm not the only developer using it this way.

~~~
ismarc
Additionally, there's significant benefit to lots of tiny commits with a 1
sentence what changed and the squash the commits and write the larger, better
formatted one based on your list of one-liners.

~~~
pbiggar
I am completely sold on a large series of tiny commits. I am not sold on
squashing them together. Why do that?

~~~
ismarc
I frequently have a commit history that looks something like:

    
    
        * Add call stub to Foo, add calls to the stub where needed
        * Beginnings of implementation, seems really friggin slow right now.
        * Ok, back to square one, need calls to X, Y and Z, can be chained together, wrap behind the call we actually need.
        * Final implementation
    

Which I then may leave comments in the code about the obvious approach that
didn't work, or why it is the way it is. I then squash this into two commits,
first one covering the implementation added to Foo with an appropriate
descriptive commit message and a second commit after it that actually uses the
new implementation.

Most of the incomplete commits aren't necessary, but we only develop on topic
branches and I have a desktop I use at work and a laptop that travels to and
from work with me (in case of deciding to work at a coffeeshop, or want to
kick back, etc.). The ability to push not-yet-done work to my topic branch
makes it available to either computer and the committing when halfway through
because it's time to not be at the desk can easily be fixed with squashed
commits.

~~~
pbiggar
Ah, so we're not talking about taking a whole branch and squashing it into a
single 2000 line commit called "Implemented at FooBar" then?

------
decklin
On a similar note, I like to periodically clean out my shell history by
dropping commands less than a certain Levenshtein edit distance from earlier
commands[1]. Looking at the removed lines would probably produce further ideas
for optimizing commands; I'll have to try it next time.

[1] rudimentary script: <https://github.com/decklin/bin/blob/master/hprune>
(haven't bothered to add real option parsing or make it efficient; for shell
histories of thousands of lines you probably want to up the search depth to
something in the hundreds)

------
halostatue
Interesting analysis, once I got it to work. (I have my zsh configured to put
history in ~/.zsh_cache/history, not one of the default files. I don't use oh-
my-zsh, either.)

If I get to the point where I want to play with this, I'll probably fork it
and propose some changes back. It also strongly suggests that I should blow
away my history because there's some unusual values reported because of my
work.

------
samspot
I was inspired by this to share the rebuild alias I've finally come up with:

    
    
      sf = tcstop && mvp stretch-base,stretch-app && tcs
        tcstop = ~/tomcat6/bin/catalina.sh stop
        mvp = mvn package -projects
        tcs = cl && tcstart && sti
    		cl = cleard; cleari; cleare; cleart
    			cleard = find /cygdrive/c/var/log/tomcat6/*.debug -exec truncate -s 0 {} \;
    			cleari = find /cygdrive/c/var/log/tomcat6/*.info -exec truncate -s 0 {} \;
    			cleare = find /cygdrive/c/var/log/tomcat6/*.err -exec truncate -s 0 {} \;
    			cleart = find /home/sthomas/tomcat6/logs/catalina.out -exec truncate -s 0 {} \;
    		tcstart = ~/tomcat6/bin/catalina.sh start
    		sti = tail -f /cygdrive/c/var/log/tomcat6/*.info ~/tomcat6/logs/catalina.out

------
pkrumins
Also see an old article of mine titled "Working with git? These aliases will
save you hours!":

<http://www.catonmat.net/blog/git-aliases/>

------
notatoad
Is typing git commit over and over again really so terrible? It's pretty much
muscle memory anyways.

Personally, I like to leave my setup as stock as possible, so I can still be
productive regardless of whose computer I happen to be using.

~~~
DeepDuh
Whenever there is an argument of a CLI being suboptimal you can be sure that
the counter is going to be "but it's all in my muscle memory!". CLI itself
isn't efficient, it just FEELS efficient. Its real strength is the
scriptability, such that repeating tasks can be substituted. If you deny
yourself that power, you'd probably be better off with a GUI and good use of
hotkeys.

Now, I'm aware that there are different usage scenarios. A typical developer
only ever works on a handful of systems at the same time period - which makes
handling your personal set of scripts a viable option. Administrators are an
entirely different beast.

~~~
mhd
I'd say that administrators who can't set up a system that allows them to have
individual setups maybe should pick another job. Even if you're sharing a root
account, you could still source your unique shortcuts and aliases. The only
thing prevent you from doing that is privileges, of course (although even then
there are partial workarounds).

But there is a point about optimizing typing. If you're just going to replace
"git" with "g", you'll save two characters. You're probably not quite down to
a third of the time, but there will be a measurable difference. But given that
there's some overlap with other actions (e.g. you might already be pondering
your commit message), the measured productivity increase will probably be
pretty small.

In cases like that, it's probably better to look at the whole workflow, so
you're not just saving time at the micro level. Save/unify several steps of
the whole procedure (e.g. combine save-commit in your text editor).

And then consider that by reading this thread, you've spent x minutes that
you'd have to work very hard to get back by saving keystrokes ;)

------
techpeace
For improving your git-command-related efficiency, you could always use the
excellent git-sh by Ryan Tomayko (CTO of GitHub):
<https://github.com/rtomayko/git-sh>

~~~
stretchwithme
Tower is pretty awesome too if you aren't wedded to the command line. I can do
things in seconds that would take me awhile to figure out how to do on the
command line.

------
JustinSeriously
For a bare-bones approach, this shell command would also do the trick.

cut -d\ -f1 ~/.bash_history | sort | uniq -c | sort -rn | head

(Note: There should be two spaces after the -d\ .)

~~~
socmoth
(disclaimer: this is my link/blog/software)

If that doesn't work for you, this might:

history 1 | awk '{print $2}' | awk 'BEGIN {FS="|"}{print $1}' | sort | uniq -c
| sort -n | tail | sort -nr

What that doesn't give you is the command tree, for example "git commit" vs
"git checkout". It just does "git".

[edit, added gem link] The gem is here <https://github.com/paulmars/huffshell>

~~~
psykotic
Generating the word tree is short and simple, though. It's also useful as a
standalone Unix utility. Here's my one-minute hack:

    
    
        import sys
        import collections
    
        tree = lambda: collections.defaultdict(lambda: [0, tree()])
    
        def printtree(node, indent=0):
            padding = indent * ' '
            for word, (count, child) in node.iteritems():
                print "%s%s %d" % (padding, word, count)
                printtree(child, indent + 2)
    
        wordtree = tree()
        for line in sys.stdin:
            node = wordtree
            for word in line.split():
                node[word][0] += 1
                node = node[word][1]
        printtree(wordtree)

------
TazeTSchnitzel
I keep forgetting that bash has tab completion. I only found out when I got
fish.

