156
votes

We all know how to use <ctrl>-R to reverse search through history, but did you know you can use <ctrl>-S to forward search if you set stty stop ""? Also, have you ever tried running bind -p to see all of your keyboard shortcuts listed? There are over 455 on Mac OS X by default.

What is your single most favorite obscure trick, keyboard shortcut or shopt configuration using bash?

6
  • 2
    Please reword this to say "What is your single most favourite". This allows people to up-vote specific answers, almost like a poll. Commented Sep 16, 2008 at 1:08
  • > Please reword this to say "What is your single most favourite". Done. Commented Oct 2, 2008 at 22:05
  • 1
    There is a StackOverflow clone for this very question: commandlinefu.com Commented Apr 15, 2009 at 16:54
  • Only 232 of those 455 default key-bindings do something other than "self-insert" ("type this key"): $ bind -p |grep -v self-insert | wc Commented Jun 2, 2009 at 10:57
  • Some neat stuff in here. But it should be noted that a quite a few of them only work when the bash is in emacs mode... Commented Sep 10, 2009 at 16:03

105 Answers 105

156
votes

Renaming/moving files with suffixes quickly:
cp /home/foo/realllylongname.cpp{,-old}

This expands to:
cp /home/foo/realllylongname.cpp /home/foo/realllylongname.cpp-old

Sign up to request clarification or add additional context in comments.

1 Comment

Just to point out that to do the reverse (going from .cpp-old to .cpp) you'd do cp /home/foo/realllylongname.cpp{-old,}
149
votes
cd - 

It's the command-line equivalent of the back button (takes you to the previous directory you were in).

4 Comments

I prefer to use pushd and popd to maintain a directory stack, myself.
But 'cd -' has the advantage of working even if you didn't remember to use pushd.
It's worth mentioning that 'cd' takes you to your home directory.
It's interesting that this doesn't show up in man cd or, cd --help (at least mine).
135
votes

Another favorite:

!! 

Repeats your last command. Most useful in the form:

sudo !! 

5 Comments

it has the added benefit of making you sound really angry about it too. "Computer, do this." "Access denied". "DO IT!!"
That's not little known! :-)
Similar things you can do: mkdir testdir; cd !$.. This runs cd [last word of previous line] (in the example, cd testdir)
Make Me A Sandwich Sudo !!
If you like !!, !$ and !-1:^foo^bar, you'll also "bind Space:magic-space". stackoverflow.com/questions/603696/…
80
votes

My favorite is '^string^string2' which takes the last command, replaces string with string2 and executes it

$ ehco foo bar baz bash: ehco: command not found $ ^ehco^echo foo bar baz 

Bash command line history guide

4 Comments

This is non-greedy. How do I make it greedy?
!!:gs/ehco/echo/
The 2nd page of that guide is essential
@andre-r: !!:gs/ehco/echo/ performs a global search and replace on the last command (confer !! in stackoverflow.com/questions/68372/…). That is not equivalent to ^ehco^echo which just replaces one instance of "ehco" -- a more accurate response would be !!:s/ehco/scho.
64
votes

rename

Example:

$ ls this_has_text_to_find_1.txt this_has_text_to_find_2.txt this_has_text_to_find_3.txt this_has_text_to_find_4.txt $ rename 's/text_to_find/been_renamed/' *.txt $ ls this_has_been_renamed_1.txt this_has_been_renamed_2.txt this_has_been_renamed_3.txt this_has_been_renamed_4.txt 

So useful

4 Comments

Wow, I've been a moron all these years using basename, mv and {} tricks to do this. /foreheadsmack.
rename isn't bash/readline specific like the other posts however.
zmv from zsh distribution is much better in most cases.
util-linux-ng has a rename command too and it's not like the one mentioned in this answer. The command described here is actually mmv.
60
votes

I'm a fan of the !$, !^ and !* expandos, returning, from the most recent submitted command line: the last item, first non-command item, and all non-command items. To wit (Note that the shell prints out the command first):

$ echo foo bar baz foo bar baz $ echo bang-dollar: !$ bang-hat: !^ bang-star: !* echo bang-dollar: baz bang-hat: foo bang-star: foo bar baz bang-dollar: baz bang-hat: foo bang-star: foo bar baz 

This comes in handy when you, say ls filea fileb, and want to edit one of them: vi !$ or both of them: vimdiff !*. It can also be generalized to "the nth argument" like so:

$ echo foo bar baz $ echo !:2 echo bar bar 

Finally, with pathnames, you can get at parts of the path by appending :h and :t to any of the above expandos:

$ ls /usr/bin/id /usr/bin/id $ echo Head: !$:h Tail: !$:t echo Head: /usr/bin Tail: id Head: /usr/bin Tail: id 

2 Comments

the 'echo !!2' didn't work for me and from a later post I saw that I think it's supposed to be: 'echo !:2'
add "bind Space:magic-space" to .bashrc and any ! combination will be automatically expanded when you hit space.
47
votes

When running commands, sometimes I'll want to run a command with the previous ones arguments. To do that, you can use this shortcut:

$ mkdir /tmp/new $ cd !!:* 

Occasionally, in lieu of using find, I'll break-out a one-line loop if I need to run a bunch of commands on a list of files.

for file in *.wav; do lame "$file" "$(basename "$file" .wav).mp3" ; done; 

Configuring the command-line history options in my .bash_login (or .bashrc) is really useful. The following is a cadre of settings that I use on my Macbook Pro.

Setting the following makes bash erase duplicate commands in your history:

export HISTCONTROL="erasedups:ignoreboth" 

I also jack my history size up pretty high too. Why not? It doesn't seem to slow anything down on today's microprocessors.

export HISTFILESIZE=500000 export HISTSIZE=100000 

Another thing that I do is ignore some commands from my history. No need to remember the exit command.

export HISTIGNORE="&:[ ]*:exit" 

You definitely want to set histappend. Otherwise, bash overwrites your history when you exit.

shopt -s histappend 

Another option that I use is cmdhist. This lets you save multi-line commands to the history as one command.

shopt -s cmdhist 

Finally, on Mac OS X (if you're not using vi mode), you'll want to reset <CTRL>-S from being scroll stop. This prevents bash from being able to interpret it as forward search.

stty stop "" 

8 Comments

I find "Alt-." much better than "!!:*" for repeating the last word of the last command.
Additions for histroy: 1. regularly save history (with -a if you have multiple shells open at once) export PROMPT_COMMAND="history -a" 2. Alias for reading the history from other shells. alias -- h='history -n ; history | grep '
export HISTIGNORE="[ ]*" is not necessary, as your HISTCONTROL=ignoreboth should do the same
Another nice thing for history: export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S : "
To save a few keystrokes off of "cd !!:*", try "cd !$". The "!$" will be interpreted as the last argument of your last command.
|
43
votes

How to list only subdirectories in the current one ?

ls -d */ 

It's a simple trick, but you wouldn't know how much time I needed to find that one !

5 Comments

Excellent! All these years the best I could come up with was alias lsd='ls -F | grep --color /', which would list the same thing but in a more lame fashion. However, it would list one dir per line, for ease of parsing. I've modified your command to do the same: ls -d1 */
how does this work? "ls -d" lists just . (which is weird) but "ls -d */" works.
It is a bit tricky... "ls -d" is similar to "ls -d ./" and "ls -d /" to "ls -d ./*/". The '-d' switch set 'ls' tu list only directory entries, but if you give it no parameter, it use the current directory as a parameter, so it has *only the "." directory to list...
I can't believe I've never discovered this before. Great tip.
No words, just wow!!! :)
41
votes

ESC.

Inserts the last arguments from your last bash command. It comes in handy more than you think.

cp file /to/some/long/path 

cd ESC.

6 Comments

This works for me (bash). Note that you hit the esc key and then the period key. No hyphen or anything.
Also alt-. is the same thing.
Yeah, it's Bash only. But <esc> (or Alt- or Meta-) _ is bound to the same function, and <esc>-_ also works in vi-mode too.
@hendry in my zsh it actually works. Maybe you use vi mode?
Use the kbd-tag for keyboard hits: <kbd>ESC</kbd> (But doesn't play very nice together with code-formatting/indentation).
|
36
votes

Sure, you can "diff file1.txt file2.txt", but Bash supports process substitution, which allows you to diff the output of commands.

For example, let's say I want to make sure my script gives me the output I expect. I can just wrap my script in <( ) and feed it to diff to get a quick and dirty unit test:

$ cat myscript.sh #!/bin/sh echo -e "one\nthree" $ $ ./myscript.sh one three $ $ cat expected_output.txt one two three $ $ diff <(./myscript.sh) expected_output.txt 1a2 > two $ 

As another example, let's say I want to check if two servers have the same list of RPMs installed. Rather than sshing to each server, writing each list of RPMs to separate files, and doing a diff on those files, I can just do the diff from my workstation:

$ diff <(ssh server1 'rpm -qa | sort') <(ssh server2 'rpm -qa | sort') 241c240 < kernel-2.6.18-92.1.6.el5 --- > kernel-2.6.18-92.el5 317d315 < libsmi-0.4.5-2.el5 727,728d724 < wireshark-0.99.7-1.el5 < wireshark-gnome-0.99.7-1.el5 $ 

There are more examples in the Advanced Bash-Scripting Guide at http://tldp.org/LDP/abs/html/process-sub.html.

Comments

35
votes

My favorite command is "ls -thor"

It summons the power of the gods to list the most recently modified files in a conveniently readable format.

4 Comments

Reminds me of another, totally useless but also funny command: ls -bart -simpson -ruls. S, ICNR
'ls -tor' is also useful since you can quickly find large files. And also, the original Swedish spelling of the name of the god of thunder is actually 'Tor'.
In Danish you can use ls -lort which is the Danish word for "shit". Omitting any groups and not getting the wrath of valhal :)
one could also say it like "ls -lotr" which apparently has something to do with Tolkien and Lord Of The Rings :)
27
votes

More of a novelty, but it's clever...

Top 10 commands used:

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

Sample output:

 242 git 83 rake 43 cd 33 ss 24 ls 15 rsg 11 cap 10 dig 9 ping 3 vi 

1 Comment

Here's a shorter, faster version: history | awk 'BEGIN {FS="[ \t]+|\\|"} {print $3}' | sort | uniq -c | sort -nr | head
25
votes

^R reverse search. Hit ^R, type a fragment of a previous command you want to match, and hit ^R until you find the one you want. Then I don't have to remember recently used commands that are still in my history. Not exclusively bash, but also: ^E for end of line, ^A for beginning of line, ^U and ^K to delete before and after the cursor, respectively.

3 Comments

I can never remember ^U for some reason. Isn't there a word delete delete shortcut too?
^W deletes the word before the cursor. (Feel free to edit your answer with this.)
^R being so useful that it was mentioned in the question :)
20
votes

I often have aliases for vi, ls, etc. but sometimes you want to escape the alias. Just add a back slash to the command in front:

Eg:

$ alias vi=vim $ # To escape the alias for vi: $ \vi # This doesn't open VIM 

Cool, isn't it?

1 Comment

You can also run command—see SHELL BUILTIN COMMANDS in the Bash manual.
17
votes

Here's a couple of configuration tweaks:

~/.inputrc:

"\C-[[A": history-search-backward "\C-[[B": history-search-forward 

This works the same as ^R but using the arrow keys instead. This means I can type (e.g.) cd /media/ then hit up-arrow to go to the last thing I cd'd to inside the /media/ folder.

(I use Gnome Terminal, you may need to change the escape codes for other terminal emulators.)

Bash completion is also incredibly useful, but it's a far more subtle addition. In ~/.bashrc:

if [ -f /etc/bash_completion ]; then . /etc/bash_completion fi 

This will enable per-program tab-completion (e.g. attempting tab completion when the command line starts with evince will only show files that evince can open, and it will also tab-complete command line options).

Works nicely with this also in ~/.inputrc:

set completion-ignore-case on set show-all-if-ambiguous on set show-all-if-unmodified on 

2 Comments

+1 bash_completion is awesome
On a Mac, the History search with arrow keys can be enabled with: bind '"\e[A"':history-search-backward bind '"\e[B"':history-search-forward
17
votes

I use the following a lot:

The :p modifier to print a history result. E.g.

!!:p 

Will print the last command so you can check that it's correct before running it again. Just enter !! to execute it.

In a similar vein:

!?foo?:p 

Will search your history for the most recent command that contained the string 'foo' and print it.

If you don't need to print,

!?foo 

does the search and executes it straight away.

2 Comments

Instead of using :p, you can also use magic-space: stackoverflow.com/questions/603696/…
to expand the historical controls without running confiure magick-space in bashrc bind Space:magic-space # !pin<space>
16
votes

I have got a secret weapon : shell-fu.

There are thousand of smart tips, cool tricks and efficient recipes that most of the time fit on a single line.

One that I love (but I cheat a bit since I use the fact that Python is installed on most Unix system now) :

alias webshare='python -m SimpleHTTPServer' 

Now everytime you type "webshare", the current directory will be available through the port 8000. Really nice when you want to share files with friends on a local network without usb key or remote dir. Streaming video and music will work too.

And of course the classic fork bomb that is completely useless but still a lot of fun :

$ :(){ :|:& };: 

Don't try that in a production server...

4 Comments

I guess i shouldn't webshare /
I guess you can simplify the command to python -m SimpleHTTPServer (unless I'm missing something fancy the original command does
Meh. On a production server that fork bomb will just get squelched by the OS; there are limits on the number of processes that any user can create.
@Donal: You should try it and report your findings.
12
votes

You can use the watch command in conjunction with another command to look for changes. An example of this was when I was testing my router, and I wanted to get up-to-date numbers on stuff like signal-to-noise ratio, etc.

watch --interval=10 lynx -dump http://dslrouter/stats.html 

2 Comments

The watch command is really cool. I first read about in the Linux Server Hacks book about five years ago. Who knew it existed?
What in the world does 'watch' have to do with bash?
11
votes
type -a PROG 

in order to find all the places where PROG is available, usually somewhere in ~/bin rather than the one in /usr/bin/PROG that might have been expected.

1 Comment

It will also tell you if it's a function or alias. If it's in multiple places in your PATH it will show each of them.
11
votes

I like to construct commands with echo and pipe them to the shell:

$ find dir -name \*~ | xargs echo rm ... $ find dir -name \*~ | xargs echo rm | ksh -s 

Why? Because it allows me to look at what's going to be done before I do it. That way if I have a horrible error (like removing my home directory), I can catch it before it happens. Obviously, this is most important for destructive or irrevocable actions.

4 Comments

You might want to use find -print0 and xargs -0 to avoid problems with files and folders with white spaces in them.
Or avoid creating and working with files and folders with white spaces in their names. ;-) Obviously if you are working with user generated names, your suggestion is vital.
Why would you append "| ksh -s" when you could just remove the "echo"?
No need to pipe with GNU find: $ find dir -name \\*~ -exec rm {} +
10
votes

When downloading a large file I quite often do:

while ls -la <filename>; do sleep 5; done 

And then just ctrl+c when I'm done (or if ls returns non-zero). It's similar to the watch program but it uses the shell instead, so it works on platforms without watch.

Another useful tool is netcat, or nc. If you do:

nc -l -p 9100 > printjob.prn 

Then you can set up a printer on another computer but instead use the IP address of the computer running netcat. When the print job is sent, it is received by the computer running netcat and dumped into printjob.prn.

3 Comments

Why this and not, for example, wget?
Try watch ls -la <filename> (use -n5 if you don't like the default of 2 seconds).
@Ted, watch is not available on all platforms though, like Solaris, Mac OS X, etc. @Porges, not sure what you mean. Can wget also listen on a port?
10
votes

pushd and popd almost always come in handy

Comments

10
votes

One preferred way of navigating when I'm using multiple directories in widely separate places in a tree hierarchy is to use acf_func.sh (listed below). Once defined, you can do

cd --

to see a list of recent directories, with a numerical menu

cd -2

to go to the second-most recent directory.

Very easy to use, very handy.

Here's the code:

# do ". acd_func.sh" # acd_func 1.0.5, 10-nov-2004 # petar marinov, http:/geocities.com/h2428, this is public domain cd_func () { local x2 the_new_dir adir index local -i cnt if [[ $1 == "--" ]]; then dirs -v return 0 fi the_new_dir=$1 [[ -z $1 ]] && the_new_dir=$HOME if [[ ${the_new_dir:0:1} == '-' ]]; then # # Extract dir N from dirs index=${the_new_dir:1} [[ -z $index ]] && index=1 adir=$(dirs +$index) [[ -z $adir ]] && return 1 the_new_dir=$adir fi # # '~' has to be substituted by ${HOME} [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}" # # Now change to the new dir and add to the top of the stack pushd "${the_new_dir}" > /dev/null [[ $? -ne 0 ]] && return 1 the_new_dir=$(pwd) # # Trim down everything beyond 11th entry popd -n +11 2>/dev/null 1>/dev/null # # Remove any other occurence of this dir, skipping the top of the stack for ((cnt=1; cnt <= 10; cnt++)); do x2=$(dirs +${cnt} 2>/dev/null) [[ $? -ne 0 ]] && return 0 [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}" if [[ "${x2}" == "${the_new_dir}" ]]; then popd -n +$cnt 2>/dev/null 1>/dev/null cnt=cnt-1 fi done return 0 } alias cd=cd_func if [[ $BASH_VERSION > "2.05a" ]]; then # ctrl+w shows the menu bind -x "\"\C-w\":cd_func -- ;" fi 

Comments

10
votes

Expand complicated lines before hitting the dreaded enter

  • Alt+Ctrl+eshell-expand-line (may need to use Esc, Ctrl+e on your keyboard)
  • Ctrl+_undo
  • Ctrl+x, *glob-expand-word

$ echo !$ !-2^ * Alt+Ctrl+e
$ echo aword someotherword * Ctrl+_
$ echo !$ !-2^ * Ctrl+x, *
$ echo !$ !-2^ LOG Makefile bar.c foo.h

&c.

2 Comments

+1, I am always afraid of pressing Enter :)
Didn't know any of these. Undo is a killer. Good for any command line editing.
9
votes

I've always been partial to:

ctrl-E # move cursor to end of line ctrl-A # move cursor to beginning of line 

I also use shopt -s cdable_vars, then you can create bash variables to common directories. So, for my company's source tree, I create a bunch of variables like:

export Dcentmain="/var/localdata/p4ws/centaur/main/apps/core" 

then I can change to that directory by cd Dcentmain.

5 Comments

Home and End do the same things as crtl-A and ctrl-E.
This helps on Mac Laptops that don't have home and end keys.
Unfortunately ctrl-A is also the escape key for screen by default. I remap it to ctrl-X in my .screenrc, but then I'm not an emacs user.
Somewhat related to the cdable_vars option, there's also the CDPATH environment variable. But that works differently, because you set the parent directory, much like in PATH. With cdable_vars you get more control.
More for your shortcut list: CTRL+K to delete everything from cursor to end of line, CTRL+U to delete everything before cursor, ALT+F/ALT+B to move one word forward/backward (or CTRL+left arrow/CTRL+right arrow). +1 for cdable_vars!
8
votes

pbcopy

This copies to the Mac system clipboard. You can pipe commands to it...try:

pwd | pbcopy

2 Comments

N.B! This is a Mac specific command.
These aren't: alias pbcopy='xsel --clipboard --input' and alias pbpaste='xsel --clipboard --output'
7
votes
$ touch {1,2}.txt $ ls [12].txt 1.txt 2.txt $ rm !:1 rm [12].txt $ history | tail -10 ... 10007 touch {1,2}.txt ... $ !10007 touch {1,2}.txt $ for f in *.txt; do mv $f ${f/txt/doc}; done 

1 Comment

Use history 10 instead of history | tail -10 (which should be tail -n 10 by the way since that syntax is deprecated).
7
votes

Using 'set -o vi' from the command line, or better, in .bashrc, puts you in vi editing mode on the command line. You start in 'insert' mode so you can type and backspace as normal, but if you make a 'large' mistake you can hit the esc key and then use 'b' and 'f' to move around as you do in vi. cw to change a word. Particularly useful after you've brought up a history command that you want to change.

Comments

7
votes

Similar to many above, my current favorite is the keystroke [alt]. (Alt and "." keys together) this is the same as $! (Inserts the last argument from the previous command) except that it's immediate and for me easier to type. (Just can't be used in scripts)

eg:

mkdir -p /tmp/test/blah/oops/something cd [alt]. 

2 Comments

Also try combining it with Alt-[0-9] (hit the first combination, then release, then the second). e.g. if last command was 'mv foo bar', then "Alt-0 Alt-." gives 'mv', "Alt-1 Alt-." gives 'foo', "Alt-2 Alt-." and basic Alt-. both give 'bar', etc.
Also try pressing Alt-. more than once (or press down Alt, hold it there, press dot many times, and then release Alt) This is similar to pressing Ctrl-R more than once.
7
votes

String multiple commands together using the && command:

./run.sh && tail -f log.txt 

or

kill -9 1111 && ./start.sh 

2 Comments

if one fail, the other command wont be executed (fail fast, like in programmation)
The opposite is to use the logical or '||' in which the right hand side will only be executed if the left hand side is false. Example: <code>command_1 || command_2</code>

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.