Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Share your command line features and tricks for Unix/Linux. Try to keep it shell/distro agnostic if possible. Interested in seeing aliases, one-liners, keyboard shortcuts, small shell scripts, etc.


locked by Michael Mrozek Nov 6 '11 at 0:41

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

63 Answers 63

find path expr -exec ls -ld {} \;

Nice easy way to see ownership, permissions, sizes (if files), and other characteristics of whatever your 'find' expression returns.


ReTTY, which allows you to move a running program from one terminal to another. That way, if you have an ncurses program running outside of screen, tmux, or ssh, you can attach it to an ssh session or a networked screen or tmux session by running ReTTY inside the terminal where you want to use the program in question. In other words, it is similar to screen and tmux but with the exceptions that (a) it can only run one program at a time, and (b) it can be run after you start the child process.


I often notice, just after starting a 15-minute-command, that I would have wanted to add some other stuff to the command line using && . Instead of interrupting the already-running job, I tend to use at to queue the second one, giving myself a longer time I don't need to watch the terminal.

Generally, at queues jobs for execution at a given time:

$ at 14:30
> myscript
> anotherscript
> <CTRL-D>

Entries to the queue can be viewed with atq and removed with atrm.

Another addition to the bash prompt customization tips: I like to invert the prompt, as this gives good visual cues where command output begins and ends in long terminal listings. This works well for both bright and dark backgrounds.

export PS1="\[\e[7m\][\u@\h \w]\[\e[0m\]$ "

My favs are below. I use most of them regularly

df -k (check filesystems) kill or kill -9 (kill a process) set -o vi (set your command line to vi) topas (performance tool) mount/unmount

oh yeah and how could I forget the > (to redirect output to a file) ls > /tmp/tmp.txt

Many more but some off the top of me head.


zsh's auto pushd feature:

setopt autopushd

and together with that:

alias dirs='dirs -v'

So that at any time, I can type dirs and I get the history of where I have been:

0   /var/log
1   /tmp
2   /usr/local/bin
3   ~

and then I can cd back into e.g. /usr/local/bin by typing:

cd ~2

double star expansion with zsh (which recursively descends the directory tree, not just one level, something similar to $(find ! -type d):

grep string **/*.cc

I find understanding bash key strokes leads to more efficient shelling, and that a lot of them are straight from emacs clarifies their usage (i.e. that meta-XXX is the big brother version of ctrl-XXX command usually).

The "meta" key is usually the "alt" key, but can also be "esc" key. e.g. meta-f can be got with either alt-f or esc f.

For the alt- key mappings to work, you may have to unset "menu access keys" or its equivalent in the console options. Basically if you press alt-f and get the file menu prompt, turn off the alt-key access menus.

ctrl-a / ctrl-e : move to start / end of line basics you can't do without

ctrl-f, meta-f : forward char/word pressing alt-f jumps you forward "1 word" which on command line is pretty much a command or argument

ctrl-b, meta-b : backwards char/word same as alt-f, but backwards to jump backwards through the command line

ctrl-d, meta-d : delete char/word pressing alt-d will delete (to end of) current word under cursor. much faster then holding delete down for 30 secs. Useful when you're tab completing in the middle of something and want to forward delete to the end of word.

ctrl-k : kill line deletes to the end of line

ctrl-u : undo e.g. typing a password, and you know you've got it wrong somewhere, instead of hitting backspace 20 times, just hit ctrl-u. also clears the current command line.

meta-# : insert comment this is great for keeping your command line you're building up as a comment before running it if you need to do something else first. it will go into your command history but not run.

ctrl-r : reverse search searching backwards through your shell history (repeated ctrl-r for next match)

ctrl-g : abort if you're in middle of ctrl-r and want to just get back to where you were typing, just abort your search with ctrl-g

meta-space / ctrl-x ctrl-x : set mark and jump to mark if you need to quickly jump to a position in your command line, first set the mark, then jump back to it with ctrl-x ctrl-x. Note you may have to use esc-space to get the mark set as alt-space is often bound to bringing down the console menu.

ctrl-] <char> : quick jump to <char> jumps forward to the character typed after the ctrl-] on command line. The big brother Meta-ctrl-] <char> jumps backwards.


Summarize directory size, with descending human size

du -hs */ | sort -hr


10.2G   foo/
4M      bar/

get the file name with the most recent timestamp in the current directory:

latest () { ls -lrt | tail -1 | awk '{print $NF}' }


My favorite is

man 7 ascii

Simple and so very useful.

alt text

Have a look at this website commandlinefu.com.

You can also have a look at these four articles by Peteris Krumins on his blog

The separate ascii program is also useful. Besides printing a table, it lets you query for one or more individual characters. – Matthew Flaschen Aug 15 '10 at 5:24

Backup your fancy dot files automagically

Modular .bashrc --> .bashrc.d

mkdir -p ~/.bashrc.d
cat<<'EOF' >> ~/.bashrc
echo ""
echo -n ".bashrc.d warming up: "
for script in ~/.bashrc.d/* ; do
  if [ -x "$script" ] ; then
    echo -n "${script##*/} "
    . "$script"
echo ""
echo ""
echo "  All systems are go."
echo ""

Safer rm, compatible with Linux and Mac OS X

rm() {
  local src
  local final_status=0

  for src in "$@"; do
    # Process only non command-line arguments.
    if [[ "$src" != -* ]]; then
      local trash="$HOME/.Trash"
      if [ ! -e "$src" ]; then
        echo "Safer rm: $src: No such file or directory."
      # Create the trash directory if needed.
      if [ ! -d "$trash" ]; then
        # Assume Mac trash, but it'll work on *nix too.
        mkdir -p "$trash"
        if [ ! -d "$trash" ]; then
          echo "Safer rm: Unable to create trash directory $trash"
          echo ""
          echo "   Nothing moved or deleted.  Consider carefully:"
          echo ""
          echo "      /bin/rm -rf $src"
          return 1
      local dest="$trash/${src##*/}"

      # Find a filename combination which does not already exist.
      if [ -e "$dest" ]; then
        # Try appending ISO datetime.
        dest="$dest.$(date +%Y-%m-%dT%H-%M-%S)"
        if [ -e "$dest" ]; then
          local n=1
          # Try increasing monotony.
          while [ -e "$dest.$n" ]; do
            n = $[n + 1]
      echo -n "Safer rm: Trashing $src to $dest ..."
      /bin/mv "$src" "$dest"
      echo " done."
      echo ""
      echo "  To restore:  /bin/mv     '$dest' '$src'"
      echo ""
      echo "  To purge:  /bin/rm -rf '$dest'"
      echo ""
      echo ""
  return $final_status

Super hot 'cd' up action

# Don't ask why I need 15 levels of cd ..

alias ..='cd ..'
alias .2='cd ../..'
alias ...='.2'
alias .3='cd ../../..'
alias .4='cd ../../../..'
alias .5='cd ../../../../..'
alias .6='cd ../../../../../..'
alias .7='cd ../../../../../../..'
alias .8='cd ../../../../../../../..'
alias .9='cd ../../../../../../../../..'
alias .10='cd ../../../../../../../../../..'
alias .11='cd ../../../../../../../../../../..'
alias .12='cd ../../../../../../../../../../../..'
alias .13='cd ../../../../../../../../../../../../..'
alias .14='cd ../../../../../../../../../../../../../..'
alias .15='cd ../../../../../../../../../../../../../../..'

Readline is your one true god.

bind -p | egrep -v '(not|self)' # No existential jokes included.

Terminal fonts

After looking at bazillions of fonts, I use 14 pt Monaco, Anti-aliased with iTerm2.

On Mac (Apps): Try this app that gives key bindings.

KeyCue (tm)(r)(c)($) gives context of almost ANY running app by simply holding command.


Mine favorite is to use the python command to make the temporary http server:

python -m SimpleHTTPServer

and accessing files from this machine over the lan as:

Another one is to download the tar file in extracted form as:

wget -qO - | tar xjvf -

Here the link can be any over the www and bz2 can be either gz, tgz or bz2 itself for that matter.


The screen command. It basically saves your command line session for when you come back. It's sort of a terminal manager, like a window manager. That way, in a single terminal session, you can have multiple virtual terminals going on. It's very cool.

If one uses screen, this shell function (put it into .bashrc) is extremely useful:

function scr {
    if screen -ls | grep -q Main; then
         # reattach to Main: 
         screen -xr Main
         # name session "Main":
         screen -S Main

upon typing scr, it will check if your main session exists and will attach to it. Otherwise it will create it.

I'd recommend tmux or dvtm over screen. They are more modern and cleaner replacements. – deltaray Nov 20 '11 at 3:59

This is usually in my startup script (.bashrc, .profile, whatever)

shopt goodness, check the comments:

shopt -s cdspell        # try to correct typos in path
shopt -s dotglob        # include dotfiles in path expansion
shopt -s hostcomplete   # try to autocomplete hostnames

An alias that save keystrokes: mkdir and cd into it:

mkcd () { mkdir -p "$@" && cd "$@"; }

And last but not least, I've given up on memorizing tar syntax, so:

extract () {
    if [ -f $1 ] ; then
        case $1 in
            *.tar.bz2)  tar xjf $1      ;;
            *.tar.gz)   tar xzf $1      ;;
            *.bz2)      bunzip2 $1      ;;
            *.rar)      rar x $1        ;;
            *.gz)       gunzip $1       ;;
            *.tar)      tar xf $1       ;;
            *.tbz2)     tar xjf $1      ;;
            *.tgz)      tar xzf $1      ;;
            *.zip)      unzip $1        ;;
            *.Z)        uncompress $1   ;;
            *)          echo "'$1' cannot be extracted via extract()" ;;
        echo "'$1' is not a valid file"
+1, why didn't I think of that? (extract) – MAK Sep 19 '10 at 16:48

Replace parts of the previous command:


$ echo a b c d
a b c d
$ ^b c^X
echo a X d
a X d

Great for typos:

$ mkae
-bash: mkae: command not found
$ ^ka^ak
  • The do-nothing command : as in

    while :; do :; done
  • Brace expansion in combination with for loops:

    for c in {1..3}; do :; done
  • ! operator and short circuiting operators || and &&

    [ -d /tmp/dir ] || mkdir /tmp/dir
    if ! ping; then :; fi
  • using sub shells instead of pop/push (comes in handy in scripts)

    ~$ ( cd /tmp; echo $PWD )
  • the kind-of what-is command type

    ~$ type type
    type is a shell builtin
    ~$ type ls
    ls is aliased to `ls --color=auto'
    ~$ f(){ :; }
    ~$ type f
    f is a function
    f () 
  • also very nice: here-strings

    ~$ cat <<<"here $PWD"
    here /home/yourname
  • and my favorite: redirection on a list of commands

    { w; ps; ls /tmp; } 2>/dev/null |less

Not really a one-liner but I think it's useful. Convert many files to uppercase, for example file_to_upper *php *c. There are many similar cases like converting to lower, renaming all files by suffix/prefix, etc.

file_to_upper ()
    for file in "$@"
        if [ ! -f "$file" ]; then
            echo "File $file does not exist";
            mv -f "$file" "`echo "$file" | tr '[a-z]' '[A-Z]'`"

    return 0

My favourite command is 'find', I use it everywhere... examples:

find . -name "*.log" -exec ls -l {} \; | grep "$(find . -name "*.log" -exec ls -l {} \;| nawk '{print $5}' | sort -n | tail )"

Just display heaviest files in ls -l (long) format.

Then, if you need your code with 0640 permissions, just search:

find . \( \( ! -perm 0640 \) -a \( -name "*.cpp" -o -name "*.h" \) \) -ls | nawk '{print $3"\t"$11}'

or replace:

find . \( -name "*.cpp" -o -name "*.h" \) | xargs chmod 640

Then, do you need a symbol and don't know where is it??

  for myObj in $(find . -name "*.o"); do
    gotSym=$(dump -Xany -t $myObj | grep .MY_SYMBOL)
    if ! test "x$gotSym" = "x"
      echo "OBJECT [$myObj] ========================"
      echo "$gotSym"
      echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"^

Newer files than XFILE??

find . -newer XFILE -type f

Yeah, "find" rulez!


This expands somewhat on the !! trick mentioned in this answer. There are actually a bunch of history-related commands that tend to get forgotten about (people tend to stab Up 100 times instead looking for a command they know they typed).

  • The history command will show a list of recently run commands with an event designator to the left
  • !N will substitute the command associated with event designator N
  • !-N will substitute the N th most recent command; e.g. !-1 will substitute the most recent command, !-2 the second most recent, etc.
  • As mentioned in the other answer, !! is shorthand for !-1, to quickly substitute the last command
  • !string will substitute the most recent command that begins with string
  • !?string? will substitute the most recent command that contains string

Word designators can be added on to a ! history command to modify the results. A colon separates the event and word designators, e.g. !!:0. The event designator !! can be abbreviated to just ! when using a word designator, so !!:0 is equivalent to !:0.

  • !:0 will get the command that was executed
  • !:1 will get the first argument (and !:2 the second, etc.)
  • !:2-3 will get the second and third arguments
  • !:^ is another way to get the first argument. !:$ will get the last
  • !:* will get all arguments (but not the command)

Modifiers can also be appended to a ! history command, each prefixed by a colon. Any number can be stacked on (e.g. !:t:r:p).

  • h -- Line up to the base filename
  • t -- Only the base filename
  • r -- Line up to the filename extension
  • e -- Only the filename extension
  • s/search/replacement -- Replace the first occurrence of search with replacement
  • gs/search/replacement -- Replace all occurrences of search with replacement
You, sir, are a command-line God. Even I (as if that matters ;-)) didn't know about the !:h stuff :-) – wzzrd Aug 12 '10 at 14:14
And if you're using Bash (could be the same for certain other shells), M-^ (Meta-^) expands the above history expansion operators for you, just in case you'd like to see what you're actually referring to. – Eric Smith Sep 16 '10 at 14:41
I've never found a use for the ! command things. It just seems bad to me to run a command that I'm not seeing. It'd be so easy to type !-3 instead of !-4, and who knows what could happen. Finding the line number of the command I want to run is usually more a pain than it's worth. Cool tricks though, but I've never found a real use for them. – Falmarri Dec 16 '10 at 18:37
@Falmarri I never use the !-# ones either. I do use !string to run the last command that starts with string, but I generally tab-complete it first (zsh) to make sure I'm running the right thing – Michael Mrozek Dec 16 '10 at 18:42
No! :) "Running !N will run the command ..." is a description too narrow; actually, !N will be substituted by the command ... ; and so on for all the descriptions in the answer. More correct and opening much more useful possibilities! E.g., the mentioned sudo !!. – imz -- Ivan Zakharyaschev Mar 16 '11 at 1:34

I found the following useful when constantly switching between Windows and Unix/Linux:

alias dir="ls -l"
alias copy="cp"
alias del="rm"

Once so often when you've typed a long command and before finishing it you've realized it won't work right away, because you need to run something else before (e.g. entered git commit -m "long commit message here"), you can hit ^A^K to go to the start of the line and kill it (saving into a buffer), next run a command to fix things, and finally ^Y to paste the killed command, and continue. Saves a lot of re-typing. All this, of course is when readline is in Emacs mode.

Another time-saver: mkdir -p some/nested/dirs/to/be/created creates all the dirs in a path if they're missing.


See command output updated every n seconds

watch -n 60 df -h (displays df -h every 60 seconds)

Show statistics about network device wlan0

ip -s link ls wlan0

Show routing table for device eth1

ip route ls dev eth1

Display statistics for all routers packet travels through to reach HOST

mtr --interval 5 HOSTNAME

Consult reverse DNS records for host names on NETWORK

nmap -sL NETWORK

Benchmark a website


Get all links from a web page

lynx -dump http://www.yahoo.com | awk '/http/{print $2}'

Show default gateway

netstat -rn | awk '/UG/{print $2}'

Write standard error to a file

foo 2> errors.txt

Redirect stderr to stdout

foo 2>&1

Redirect both stderr and stdout to the same file.

foo > file.txt 2>&1
function calc() { echo $* p | dc }

dc is a RPN calculator; this function enables me to type the expression as the command arguments:

$ calc 5 3 +
# change chmod to file dowloaded --> $_

wget -c http://link/to/file -O /path/to/save/namefile && chmod 0755 $_

# extract tar.bz2 or tar.gz whit less work
# this avoids having to unpack and then move the files to another location, in this case have # already extracted in the desired location

tar jxvf file.tar.bz2 -C /pat/to/extract

# calculator with bc - in bashrc
calc(){ echo "scale=2;$@" | bc;}

# set magic-space in bashrc
bind Space:magic-space                 # !pin<space>  expand last cmd pin...

# alias to open last edited file in vim
alias lvim="vim -c \"normal '0\""

# alias to show your path set
alias path='echo -e ${PATH//:/\\n}'

Displays a nice ascii art of the current proccess tree, with the most cpu intensive proccess higlighted.

while true; do 
  pstree $( ps -eo pid --sort %cpu | tail -n 1 ); 
  sleep 1;

Kill it with Ctrl + C

I prefer using htop ;) – André Paramés Dec 16 '10 at 14:19

See this question.

When you run ps ax | grep string:

[steve@sage-arch ~]$ ps ax | grep 'openbox'
 3363 ?        Ss     0:00 /usr/bin/openbox
 3382 ?        Ss     0:00 /usr/bin/ssh-agent -- /usr/bin/openbox-session
 3386 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3388 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3389 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3390 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 5100 pts/0    S+     0:00 grep openbox

the last line containing grep is somethings a bit anoying

You can rid yourself of this by running ps ax | grep '[s]tring':

[steve@sage-arch ~]$ ps ax | grep '[o]penbox'
 3363 ?        Ss     0:00 /usr/bin/openbox
 3382 ?        Ss     0:00 /usr/bin/ssh-agent -- /usr/bin/openbox-session
 3386 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3388 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3389 ?        S      0:00 /bin/sh /usr/bin/openbox-session
 3390 ?        S      0:00 /bin/sh /usr/bin/openbox-session

update: or just run pgrep string


Brace Expansion:

Brace expansion is a mechanism by which arbitrary strings may be generated.

It allows you to replace tedious lines like:

mv loong/and/complex/file/name loong/and/complex/file/name.bacukup

with a shorter instance

mv loong/and/complex/file/name{,backup}

some other uses

# to display the diff between /etc/rc.conf and /etc/rc.conf.pacsave
diff /etc/rc.conf{,.pacsave}

# to list files in both /usr/share and /usr/local/share
ls /usr/{,local}/share 

Arithmetic Expansion:

Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is:


The expression is treated as if it were within double quotes, but a double quote inside the parentheses is not treated specially. All tokens in the expression undergo parameter expansion, string expansion, command substitution, and quote removal. Arithmetic expansions may be nested.

$ a=1
$ b=2
$ echo $(( a+(b*2) ))
Nice, I can't believe I forgot about this. There's also a more compact foo[123] that will expand into foo1 foo2 foo3, but they need to be filenames to work in that case – Michael Mrozek Sep 23 '10 at 14:31

My personal favorite is

find . -name <i>filename</i> | xargs grep -in '<i>pattern to search for</i>'

What the above command does is find a file of name x and then searches said file for whatever pattern you are looking for. Incredibly useful if you are looking for a particular bit of code in a file that's somewhere in your subdirectories.

... or ... find -iname *filename* -exec grep -in '*pattern to search for*' {} \; – Eric Smith Sep 19 '10 at 15:51
Or with recent enough versions of GNU grep: grep -r --include='filename' 'pattern' . – Gilles Oct 6 '10 at 19:26

Use pgrep foo instead of ps aux | grep foo if you want to find how many instances of foo are running and their pids:

e.g. instead of ps aux | grep firefox, use pgrep firefox


Not the answer you're looking for? Browse other questions tagged or ask your own question.