top | item 7981633

Unix Tricks

361 points| dedalus | 11 years ago |cfenollosa.com | reply

162 comments

order
[+] Tepix|11 years ago|reply
Missing trick:

In bash, "ESC" then "." fetches the last parameter of the previous command. It's invaluable (same as typing "!$" but you get to see and edit it)

[+] wazoox|11 years ago|reply
Ctrl+r is fine when you're looking for something recent, but this one is useful when you're looking through a long list of similar commands.

    alias hist='history  | grep'
Use it like this:

    $ hist git
      9543  git add toto
      9544  git commit
      9545  git log
      9546  git log
      9548  git add -A
      9549  git commit
      9550  git log
      9633  git pull
      9955  cd dev/git
      9957  git grep copyof
      9958  git grep copyof
      9959  git pull
By the way, do you know you can call back the 9633rd command in the history with "!9633"?
[+] WickyNilliams|11 years ago|reply
I use this all the time. In fact it was one of the first aliases i made when i switched to a UNIX system. Though I named mine `greph` (for grep history). Absolutely invaluable
[+] hrrsn|11 years ago|reply
Wow, this is great. All too commonly I do cat ~/.bash_history|grep, but this is way easier. Thanks!
[+] valarauca1|11 years ago|reply
Its implied on the list but not mentioned specifically.

     !! 
will be substituted with the last command you typed. So if your somebody like me who frequently types

     $ apt-get update
     Could not lock yada yada are you root?
     $ sudo apt-get update
instead you can type

     $ apt-get update
     $ sudo !!
[+] a3_nm|11 years ago|reply
It always feels more logical to me to just type "Ctrl-P Ctrl-A sudo" (previous history line, beginning of line, add missing sudo) than typing "sudo !!" or "sudo !!<tab>" if you need to edit the substitution.

Same thing for the last argument, it's easily edited if you know the right shortcuts: Ctrl-P Alt-B Ctrl-U. (Works for bash, for zsh you need http://stackoverflow.com/q/3483604/414272). That said, I didn't know about Alt-.

[+] cheepin|11 years ago|reply
What I love about this is that if you up-arrow through your past commands, the "sudo !!" shows up as "sudo apt-get update"
[+] 3rd3|11 years ago|reply

    man hier
is pretty cool. It explains the root directory structure of the system.
[+] spopejoy|11 years ago|reply
The SEE ALSO for 'man hier' alerted me to 'apropos'. Unbelievable, so much emacs goodness in bash.

"apropos Regular Expressions" brings up wild stuff: re_format(7) -- posix regex docs at last!, treereg(1) (huh????).

Some serious lore in here ...

[+] robert_tweed|11 years ago|reply
TIL. As a long-time DOS user that often gets a bit lost on Unix systems I cannot stress how awesome it is to have found out about this!
[+] danielweber|11 years ago|reply
Nice to see something I've gradually learned about by gut feel summarized.

Why do some distributions use /opt a lot while others don't seem to use it at all?

[+] smorrow|11 years ago|reply
definitely feel like this one was more widely known in the days of printed manuals.
[+] curiousHacker|11 years ago|reply
You know what I hate? My history isn't aggregated in real time across all my Mac OS X terminal windows.

You know what else I hate? Typing in long commands in the Mac OS X terminal and then them wrapping weirdly. Especially when I hit the up arrow to go back in my terminal history.

[+] Tiksi|11 years ago|reply
Here you go, just throw it in your .bashrc:

  shopt -s histappend
  export HISTSIZE=100000
  export HISTFILESIZE=100000
  export HISTCONTROL=ignoredups:erasedups
  export PROMPT_COMMAND="history -a;history -c;history -r;$PROMPT_COMMAND"
I wish I could give credit to where I originally found this but it was ages ago.
[+] diggan|11 years ago|reply

    > You know what else I hate? Typing in long commands in the Mac OS X terminal and then them wrapping weirdly.
Yeah, keeping ctrl pressed in and pressing x followed by e (CTRL + x e) will open up the current line in $EDITOR and when you edit and save, replaces the current line with what you entered in your editor. Really a killer feature.
[+] ibotty|11 years ago|reply
> My history isn't aggregated in real time across all my Mac OS X terminal windows.

zsh has `setopt inc_append_history` and `setopt share_history`. i am sure bash has something similar.

[+] Spiritus|11 years ago|reply
>You know what else I hate? Typing in long commands in the Mac OS X terminal and then them wrapping weirdly.

Are you escaping your color codes in PS1 correctly?

Bad:

    PS1="\033[1;32m \w \033[m $"
Good (notice the extra \[ and \]):

    PS1="\[\033[1;32m\] \w \[\033[m\] $"
[+] JoeAcchino|11 years ago|reply
> You know what else I hate? Typing in long commands in the Mac OS X terminal and then them wrapping weirdly.

I solved this by adding the following line in my ~/.bashrc

  shopt -s checkwinsize
Never tried on Mac OS X though, so I don't know if it works.
[+] antocv|11 years ago|reply
> Typing in long commands in the Mac OS X terminal and then them wrapping weirdly.

For all people who dont use Mac OS X:

This happens because your PS1 is wrongly set and bash cant calculate correctly the length left of your line. Try it out, by going back to default with no colors and crap and see how long it goes.

For mac os x users. The above wont help, dont even try it.

[+] toddkaufmann|11 years ago|reply
I prefer to keep mine separate, but I always use specific terminals / screen sessions for (mostly) the same type of work (admin, specific projects, web dev, etc.) so each have their own history, as well as keeping a per-directory record.

So far over 130000 command lines (with timestamp & cwd) for past 2.5 years, just on my laptop.

[+] naner|11 years ago|reply
You know what I hate? My history isn't aggregated in real time across all my Mac OS X terminal windows.

I used to feel this way. Then one day I figured out how to enable this in Bash. Resulted in a confusing mess. Turns out you most likely want terminal sessions to be distinct until you end them.

[+] jdong|11 years ago|reply
You should just move to zsh that does this natively and in a clean manner.
[+] samsaga2|11 years ago|reply
It's amazing how many years I've been using bash and I still have things to discover.

Ctrl-x Ctrl-e nice tip!

[+] pling|11 years ago|reply
I still prefer "sh" on BSD (particularly OpenBSD). It doesn't have as many knobs to turn nor as many surprises.
[+] raju|11 years ago|reply
In bash fc will open your $EDITOR with the last command you just typed. Just like Ctrl-x Ctrl-e but you don't need a command in place to edit.
[+] tomsthumb|11 years ago|reply
`man readline` and `man bash` alike blow my mind every time I pop them open.
[+] danielweber|11 years ago|reply
> - 'sort | uniq' to check for duplicate lines

sort -u

[+] WickyNilliams|11 years ago|reply
A personal favourite of mine is aliasing common cd operations.

    alias ..="cd .."
    alias ...="cd ../.."
    # etc
and of course `cd -` to jump to previous directory
[+] dorfsmay|11 years ago|reply
> In bash, 'ctrl-r' searches your command history

No! In emacs ctrl-r searches your command history. It happens that bash use emacs mode by default. All other emacs basic commands work too: ctrl-p, ctrl-n, ctrl-f etc...

If you are a vim user, and especially if you love venting how much you hate emacs, then please add this to your bashrc:

set -o vi

and now you can use vim command instead of emacs.

[+] dllthomas|11 years ago|reply
'ctrl-r' is reverse-i-search in vi mode as well.
[+] lloeki|11 years ago|reply
Instead of

    ssh -R 12345:localhost:22 server.com "sleep 1000; exit"
use

    ssh -R 12345:localhost:22 -n server.com
The -n flag tells ssh to only make a connection, without ever running a shell. This means it even works when you don't have shell access (say, with a command= entry in .authorized_keys).

Also, I cannot recommend envoy enough in lieu of ssh-agent, if you're not using a GUI ssh agent already (e.g OSX keychain or GNOME keyring)

Last, I guarantee you don't want "$@" in those aliases, but either "$*" or $@ (certainly the latter).

[+] ciupicri|11 years ago|reply
I think you meant -N, not -n. From the man page[1]:

     -N      Do not execute a remote command.  This is useful for just for‐
             warding ports (protocol version 2 only).

     -n      Redirects stdin from /dev/null (actually, prevents reading from
             stdin).  This must be used when ssh is run in the background.
[1]: http://www.openbsd.org/cgi-bin/man.cgi?query=ssh&sektion=1
[+] zipperhead|11 years ago|reply
I usually visit these threads knowing that I will pick up something useful to add to the toolbox... thank you for 'envoy' - I think it will streamline my ssh key management.
[+] voltagex_|11 years ago|reply
I wonder if I can convince the author of this to put it up in a Git repo so everyone can contribute. It probably needs the tiny URLs removed (IME, they're more likely to break than the original site)
[+] TimWolla|11 years ago|reply
You might want to try out the more modern fish shell as well: http://fishshell.com/ It makes history searching even easier.
[+] bshimmin|11 years ago|reply
I love fish and have happily been using it for years. Every time it comes up here, though, someone inevitably will complain about compatibility - and I will admit that RVM, for instance, has definitely caused me problems with fish in the past. I guess it depends quite a lot on your particular usage and requirements.
[+] currysausage|11 years ago|reply
I found Ctrl-O (execute current command from history and edit the next one) to be invaluable.

Ctrl-V: type next input literally (e.g. Ctrl-V [Tab] if you don't want [Tab] to autocomplete).

Alt-#: Prefix current line with "#" (don't execute it) and put it into history for later use.

I'm sometimes surprised how many people don't know these: Ctrl-U/K: kill line before/after cursor.

[+] thln666|11 years ago|reply
"- Compile your own version of 'screen' from the git sources. Most versions have a slow scrolling on a vertical split or even no vertical split at all"

Or you could just use tmux which afaict is superior to screen in almost every way. http://tmux.sourceforge.net/

[+] rzimmerman|11 years ago|reply
Ctrl-R is by far the most useful one for me.
[+] buerkle|11 years ago|reply
I like this in my ~/.inputrc

  "\e[A":history-search-backward
  "\e[B":history-search-forward
Type a few characters and hitting the arrow keys will show only commands that match those first few characters.
[+] cmatteri|11 years ago|reply
The article doesn't say, so it's worth mentioning that you can type ctrl-R multiple times to search further back into command history.
[+] JonnieCache|11 years ago|reply
Ctrl-P autocompletes from your history too. It works like Ctrl-R but after you've already started typing, if you see what I mean.

This might be a zsh thing though.

[+] o_____________o|11 years ago|reply
I was going to write a shell package/snippet manager until I discovered this:

https://github.com/ziyaddin/jean

It would be nice to get all of these .bash_profile enhancements in as packages.

I suppose it could be improved to prompt for a brew/apt install if needed.

[+] marcosscriven|11 years ago|reply
A really handy one a colleague showed me yesterday was the /dev/fd/0|1|2 files, which are stdin/out/err respectively. Means you can use that file for utils that expect a file only.

E.g echo "This would be contents of file" | someCommand /dev/fd/0

[+] LukeShu|11 years ago|reply
These are also available as /dev/std{in,out,err}; the names of which are a little more self documenting :)

    $ ls -l /dev/fd /dev/std* | column -t
    lrwxrwxrwx  1  root  root  13  Jun  27  16:32  /dev/fd      ->  /proc/self/fd
    lrwxrwxrwx  1  root  root  15  Jun  27  16:32  /dev/stderr  ->  /proc/self/fd/2
    lrwxrwxrwx  1  root  root  15  Jun  27  16:32  /dev/stdin   ->  /proc/self/fd/0
    lrwxrwxrwx  1  root  root  15  Jun  27  16:32  /dev/stdout  ->  /proc/self/fd/1
You can even access the file descriptors of other processes with /proc/${pid}/fd/; which is handy for (say) un-deleting a file that a process still has open.

Another handy one is "process substitution" which lets you do the same thing with multiple streams by creating new file descriptors, and automatically turning them into /dev/fd/* paths:

    someCommand <(echo "contents of file 1") <(echo "contents of file 2")
which is somewhat explained by:

    $ echo someCommand <(echo "contents of file 1") <(echo "contents of file 2")
    someCommand /dev/fd/63 /dev/fd/62