
Shell Productivity Tips and Tricks - pcr910303
https://blog.balthazar-rouberol.com/shell-productivity-tips-and-tricks.html
======
arendtio
Today, was actually the first time that I used the vim time travel feature. I
noticed that I had deleted a line by accident somewhen during the last few
minutes. So I typed

    
    
      :earlier 5m
    

and copied the line. Afterward, I typed

    
    
      :later 5m
    

and was back where I started, ready to paste the missing line :-)

~~~
ryangittins
On mornings when I'm feeling particularly lazy in the office, I'll do

    
    
      :later 8h
    

and commit the code before heading home. ;)

------
alufers
The single best shell productivity tip for me was to use z:

[https://github.com/rupa/z](https://github.com/rupa/z)

It automatically makes a list of directories you frequently use in your shell
and if you type `z a-small-substring-of-the-directory-path` it does a cd to
that directory. (e.g. I type `z and` and it changes my current directory to
$HOME/Work/Projects/android`). Saved me tons of typing.

~~~
Spivak
A somewhat less fancy version of this is $CDPATH.

    
    
       export CDPATH="/path/to/my/projects:$HOME/Work/Projects"
       # From anywhere.
       cd andr<tab><enter>

~~~
mceachen
Note that CDPATH can break shell scripts that assume `cd` hasn't been
adulterated.

A huge block of "unalias" calls at the beginning of shell scripts used to be a
common practice, but they don't seem to be found in more widely-used tools
these days.

~~~
kubanczyk
Except with CDPATH the `cd` is usually not an alias. Even `/usr/bin/cd` is
aware of CDPATH.

It's a bug in the script, just like reacting badly to $IFS or $LANG.

~~~
sigjuice
What is /usr/bin/cd for? cd is supposed to be a shell built-in, because
running /usr/bin/cd will make another process and that cannot change the
current working directory of the shell you are in.

EDIT:

    
    
      $ cat /usr/bin/cd
      #!/usr/bin/sh
      builtin cd "$@"

~~~
saagarjha
Look, it's 'cperciva!

    
    
      $ cat /usr/bin/cd
      #!/bin/sh
      # $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
      # This file is in the public domain.
      builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}

------
asicsp
I rarely use Ctrl+r to get command from history, because most of the time I
know the starting characters of the command I need. So, I type those
characters and use arrows keys to match from history. This is enabled via
these settings in .inputrc

    
    
        # use up and down arrow to match search history based on typed starting text
        "\e[A": history-search-backward
        "\e[B": history-search-forward
    

I also changed couple of setting wrt Tab autocompletion:

    
    
        # when using Tab for completion, ignore case
        set completion-ignore-case on
        # single Tab press will complete if unique, display multiple completions otherwise
        set show-all-if-ambiguous on

~~~
codegladiator
You can use ctrl+r for commands which are similar (say ssh to n number of
servers, so the up/down would still take some amount of browsing the options)

Just tag commands with a # at the end

> $ complex command here # tagHere

Later use the tag with ctrl+r

I do this all the time

> ssh 127.0.0.1 # master

~~~
asicsp
yep, ctrl+r is better suited for such cases or whenever you have to match a
command other than starting characters

and I think there are some fuzzy matching options (like fzf) that can be added
to ctrl+r

------
mstudio
fishshell is my favorite productivity enhancer for the terminal:
[https://fishshell.com/](https://fishshell.com/)

The primary reason I chose over zsh/bash was that autocompletion just works.
If you install it, I highly recommend oh-my-fish as well, which allows you to
add packages for look/functionality: [https://github.com/oh-my-fish/oh-my-
fish](https://github.com/oh-my-fish/oh-my-fish)

If you're a zsh user, they have a similar framework: oh-my-zsh:
[https://github.com/ohmyzsh/ohmyzsh](https://github.com/ohmyzsh/ohmyzsh)

~~~
ASTP001
I really enjoyed using fish for a short while, but soon I learned that it was
not POSIX compliant. This was a deal breaker for me since my colleagues would
often share scripts that wouldn't just work for me. I use zsh nowadays.

~~~
JNRowe
I _love_ zsh, but it isn't without its own strange quirks that make
compatibility _exciting_ at times. In a thread from a fortnight ago¹, RANDOM
is handled very differently for example. Try `echo $(echo $RANDOM) $(echo
$RANDOM)` in zsh and bash.

I'm unsure whether minor differences that catch you out occasionally are worse
than _huge_ differences that you always have to think about. For me zsh still
wins ;)

1\.
[https://news.ycombinator.com/item?id=22841259](https://news.ycombinator.com/item?id=22841259)

~~~
tasuki
Wow! Even repeating that call always yields the same result in zsh - as long
as it's a subshell.

I think your comment will save my sorry ass one day.

------
kortex
My productivity stack:

Zsh (with all the autocomplete plugins)

Oh-my-zsh zsh-autosuggestions: [https://github.com/zsh-users/zsh-
autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)

Tmux

Histdb: [https://github.com/larkery/zsh-
histdb](https://github.com/larkery/zsh-histdb)

Zoxide (replace cd):
[https://github.com/ajeetdsouza/zoxide](https://github.com/ajeetdsouza/zoxide)

Fzf

Rip (replace rm):
[https://github.com/nivekuil/rip](https://github.com/nivekuil/rip)

My personal dotfiles:
[https://github.com/xkortex/bashbox](https://github.com/xkortex/bashbox)

Mosh (replaces/augments ssh)

What I'm currently looking for is a better multi-host logging solution.

------
jpxw
> If you want to remove a sensitive command from your history, you can simply
> edit your $HISTFILE history file and remove it.

It’s already too late at this point. Anybody on your machine can read the
commands you are running, for example with ps. You should instinctively avoid
entering anything in plaintext into a terminal which you don’t want other
people to see. Any command line tool worth its salt will provide alternative
ways of passing secrets (using configuration files for example).

~~~
rrmm
The worst is when you expect a password prompt so you type the password and
hit enter, but you mistyped the original command and you end up typing your
password in plaintext onto the command line. oops.

~~~
McKayDavis
If you're using `bash`, A quick remedy for this is:

    
    
      unset HISTFILE
      exit
    

This prevents `bash` from updating the `~/.bash_history` file on exit with the
command you don't want memorialized. (assuming you don't also have some hook
that updates your history file after every command)

------
kubanczyk
Two big ones missing. After ctl-r history search:

    
    
      ctl-o ctl-o ctl-o   re-execute the history one by one
      
      alt-. alt-. alt-.   last argument (better ux than that !$ business)

~~~
rkangel
I didn't know either of those, thanks!

------
fdw
Some plugins that saved me lots of typing with zsh:

[https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/histo...](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/history-
substring-search) looks through your history and only shows entries that
started with the same characters that you already typed. Similar to Ctrl-R
with fzf, but still similar enough that I use both.

[https://github.com/zsh-users/zsh-autosuggestions](https://github.com/zsh-
users/zsh-autosuggestions) also looks through your history for commands with
the same start, but it will automatically suggest them for you to use. If you
often use the same commands, this saves quite some typing. For bonus points, I
hooked it up so that Ctrl-Return will execute the suggestion.

[https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/per-d...](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/per-
directory-history) To make the first two even more powerful, I split my
history based on the directory I'm in. This means that it's only suggesting me
commands I entered before in this directory.

~~~
zeppelin101
I'm a huge fan of the first 2 plugins, but I didn't know about the per-
directory history plugin. I might put that in my toolbox. Thanks for the
recommendation!

------
andreareina
Process substitution deserves a mention:
[http://www.tldp.org/LDP/abs/html/process-
sub.html](http://www.tldp.org/LDP/abs/html/process-sub.html)

------
l0b0

      **
    

is _not_ "expanded to all files and directories in the children directories,
with a depth limit of 1." It's hard to see using `ls` because `ls` doesn't
just list its arguments, it also lists files _inside_ its directory arguments.
Use

    
    
      echo **
    

and you'll see it just expands to the same as

    
    
      *
    

\- all the files in the current directory. Or type

    
    
      **
    

and press Ctrl-x, Ctrl-* (glob-expand-word) to expand it.

After `shopt -s globstar`

    
    
      **
    

expands to all files recursively.

Also, `echo $dir | tr '[:lower:]' '[:upper:]'` should be `printf '%s' "$dir" |
tr '[:lower:]' '[:upper:]'` to handle spaces and other weirdness in file
names.

(If anyone knows how to escape asterisks in HN it would be helpful to know :)

------
tcoff91
fzf fizzy history search with ctrl-r is my favorite new shell trick. Fzf is a
wonderful program

~~~
rwnspace
I too prefer fizzy history. It's like Sodastream for your shell!

Skim [0] is a nice alternative to fzf [1], mainly for the fact you can call
additional commands dynamically like so [2]:

    
    
        sk --ansi -i -c 'rg --color=always --line-number "{}"'
    

[0] [https://github.com/lotabout/skim](https://github.com/lotabout/skim) [1]
[https://github.com/lotabout/skim#difference-to-
fzf](https://github.com/lotabout/skim#difference-to-fzf) [2]
[https://github.com/lotabout/skim#interactive-
mode](https://github.com/lotabout/skim#interactive-mode)

~~~
ptzz
Would that correspond to piping the output of the additional command to fzf?

------
celeritascelery
No matter how many times I read articles like this I always manage to learn
something new. For example this time I learned about brace expansion. Will
save me retyping a bunch of commands with different text.

~~~
kreetx
Same here. I though I'd seen most of them by now but apparently not :)

echo ${MY_VAR:-some_default} is another class of useful functionality.

~~~
jldugger
sadly, i know how that works only because it was the recommended long term fix
from an RCA

------
usefulcat
If you care about your command history, I would advise against doing this
unless you are truly a sed expert:

    
    
        $ sed -i '/secret-command/d' $HISTFILE  # deletion of history line containing 'secret-command'
    

Because if you get it even slightly wrong, you could easily hose your entire
history. If it were me, I would just use an editor to delete that line (or
two, if timestamps are enabled).

~~~
wazzaps
And if you know don't want a command in your history, prefix it with a space.

------
xpuente
xargs should be there. The most useful tool IMO.

~~~
JNRowe
As zsh is mentioned at various points throughout the article I'll add that
zargs¹ is often a great alternative to xargs. Combined with zsh's awesome
globbing and filtering functionality it is often far nicer to work with than
find.

1\. [https://github.com/zsh-
users/zsh/blob/master/Functions/Misc/...](https://github.com/zsh-
users/zsh/blob/master/Functions/Misc/zargs) or zshcontrib(1)

~~~
jerzyt
I think zsh is the best shell ever, unfortunately, I've reverted to bash,
because it's too much hassle to install zsh everywhere I work. zsh globbing is
on another level.

~~~
JNRowe
> zsh globbing is on another level.

I agree. That said I'll freely admit that liberal use of glob modifiers and
qualifiers can lead to the appearance of line noise. Because of that I'll
occasionally unroll them with `find(1)`-syntax if I post a snippet to help a
co-worker, but love their expressiveness when in an interactive session.

For people not familiar with the extensive globbing options of zsh see
[https://linux.die.net/man/1/zshexpn](https://linux.die.net/man/1/zshexpn) .

------
mceachen
On more handy set of emacs-derived keystrokes:

Ctrl-a ctrl-k to clear the current command, or redo a hidden password prompt
if you know you fat-fingered it.

ctrl-a jumps the cursor to the beginning of the line, and ctrl-k deletes from
current position to the end of the line.

The mnemonic to remember these: "a" is the first position in the alphabet, and
jumps you to the first position. "K" is short for "kill.”

~~~
wazoox
Ctrl-u (delete everything from the cursor to the beginning of line) is one
less stroke for the very same result :)

~~~
usrme
Ctrl+U is also really handy for clearing password (or any other input) lines
where you know you made a mistake, but don't want to just spam Backspace until
you think you've gotten to the beginning.

------
fitzn
The article links to this at the bottom, but just calling it out again because
I think it's so useful. I am using git all the time---probably a majority of
my terminal relates to git in some way. I think the git bash completion script
is extremely useful.
[https://github.com/git/git/tree/master/contrib/completion](https://github.com/git/git/tree/master/contrib/completion)

It's incredibly easy (and transparent) to "install" and saves a ton of
keystrokes.

------
seemslegit
Best shell productivity trick ever: don't use the shell for anything more
complicated than launching executables and use a reasonably modern programming
language to achieve all other tasks.

~~~
jabl
I'd love a good answer here. Shell is clunky and annoying as hell, but a
"better" language like python is very verbose for typical shell stuff like
process management (processes, pipes, signal handling), small text handling
tasks like regex matching or string splitting.

Perl is maybe the closest here, but it certainly has it's fair share of
annoyances, and I more or less dropped perl for python decades ago and don't
particularly feel like going back.

~~~
seemslegit
Not really, with python there's a habbit-acquiring curve but you end up with
longer lasting more readable and maintainable assets that can be modularized
refactored etc. perl is write-only and has little going for it afaic but ymmv.

------
alektorophobiae
set -o vi to use vi on the command line.

------
lolive
Whoever can point me at a robust method to save/restore bash histories of a
tmux session would save my life!!! [And yes i use tmux inside tmux]

~~~
notyourday
About a year ago I went further into this rabbit hole and right now I think I
am on a re-iteration of a system I have not changed in about 4 months. It came
to me after watching too much sci-fi that had clicky-clicky-typie-typie
instant recall.

It occurred to me that every hack around history just nibbles at the edges
probably because all of them are bolted on a design when the systems were
slow. Systems now are fast and have good connectivity ( at least to themselves
) hence:

"All logins across all systems that have the same security domain share single
common command history."

I use bash but it should be adoptable to anything. Here's how it works:

1\. There's a database. I use redis because it is fast and has SETNX. [I may
switch this to a redis queue to be able to archive commands as well.]

2\. Using PROMPT_COMMAND variable I execute a function that pulls the last
executed command using "history 1" and pushes it into the database. SETNX
ensures that only a command that has not been seen before is stored. In the
same transaction I trim the number of commands stored in the database to 5000.

3\. Ctrl-R is bound to fetching last 5000 commands from the database, piping
it into "peco" which I use with the selection line on a top ("fzf" does not
support the top line so I don't use it here. "peco" does not support certain
header skips/treatments, so i use "fzf" in other places )

4\. On a failure to push into the database, system does nothing as the data is
in a local history.

5\. On a failure to pull from the database, system feeds the result of the
local history into the "peco".

This system gives me ability to access the same command line history across my
laptops, workstation, VMs, random Linux devices that i have running at home.
Our ops-team uses it across all the monitoring workstations

------
jwilk
> _Toggle your cursor between its current position and the beginning of line_

That's quite not what ^X^X does. The bash man page says:

 _Swap the point with the mark. The current cursor position is set to the
saved position, and the old cursor position is saved as the mark._

------
raykooyenga
I max out my history sizes as well as have bash functions to dump/persist them
to time stamped archives on command or on logout.

~~~
saagarjha
(That’s

    
    
      export HISTSIZE=
      export HISTFILESIZE=
    

for those wondering how to do it.)

------
kmarc
My productivity tip:

Sit down, and read through `man bash`.

Thank me later.

------
hattori
Not built-in but hstr
([https://github.com/dvorka/hstr](https://github.com/dvorka/hstr)) and tldr
([https://github.com/tldr-pages/tldr](https://github.com/tldr-pages/tldr)) are
awesome.

------
based2
vi :x

grep -n ... vi +§

