Take the 2-minute tour ×
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.

I know some people have some startup scripts and some people personalise the prompt. One developer uses short aliases for the long path he often visits and the frequent commands he runs.

What are all the effective customization you have done on your UNIX profile to increase productivity and ease of use?

share

locked by Michael Mrozek Aug 20 '12 at 13:50

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.

    
should be CW, cant be answered objectively. –  akira Jan 29 '11 at 6:49
    
I agree. However, there was no option for CW. :-( –  San Jan 29 '11 at 7:02
    
@akira @Michael I face this situation often. It would be great if moderators could edit/cross-post/redirect the question. Because the comment you leave doesn't help the user much in order to achieve what he really want. No offence, just a suggestion. Hope you understand. –  San Jan 29 '11 at 8:37
    
If you want to make a question community wiki, flag it for moderator attention. See the community wiki FAQ. –  Gilles Jan 29 '11 at 12:16

15 Answers 15

up N

jump N directories up in the directory tree

Instead of typing

cd ../../../..

you just type

up 4

and a

cd -    

will bring you back

Put the function into your .bashrc to use it.

# (c) 2007 stefan w. GPLv3          
function up {
ups=""
for i in $(seq 1 $1)
do
        ups=$ups"../"
done
cd $ups
}
share
    
Wow.. that's a nice idea.. –  San May 14 '11 at 8:11

show the most recently changed file

Often, I want to look at the most recent file. e.g., I might be in the logs directory, and want to see which file is most recent because that is the first place to look to see why something is not working.

ls -lt | head is a but cumbersome to type, so here's an alternative:

# show the most recently changed file
latest()
{
    if test $# -ne 0
    then
        /bin/ls -t -1 -d "$@" | head -n 1
    else
        /bin/ls -t -1 -d * | head -n 1
    fi
}

It also takes a wildcard or list of files, e.g.

$ latest mail* syslog*
syslog

which is especially handy if all your log files have a timestamp in their name. You can find the latest log for that program, without worrying what format the timestamp is in.

$ touch -d 'Feb 1' mylog.20110201
$ touch -d 'Feb 2' mylog.20110202
$ touch -d 'Feb 3' mylog.20110203
$ latest mylog*
mylog.20110203

And here's an extended version that supports a -<number> option to print <number> lines instead of one.

# show the most recently changed file
latest()
{
    local count=1               # how many files to print
    local promptlines=5         # how many lines to leave for the prompt
                                # when printing a screenful with -s
    local usage="Usage: latest [-n <number>] [-s] [--] [pattern]"
    while test $# -gt 0
    do
        case $1 in
        # -- = stop processing options
        --)
            shift
            break
            ;;
        # -n <number> = <number> files
        -n)
            if test -n "$2"
            then
                count=$2
                shift 2
            else
                echo "$usage" 1>&2
                return 1
            fi
            ;;
        # -s = one screenful
        -s)
            count=$((LINES - promptlines))
            shift
            ;;
        # -<number> = <number> files
        -[0-9]*)
            count=${1#-}
            shift
            ;;
        # anything else starting with a minus is a usage error
        -*)
            echo "$usage" 1>&2
            return 1
            ;;
        *)
            break
            ;;
        esac
    done

    if test $# -ne 0
    then
        /bin/ls -t -1 -d "$@" | head -n $count
    else
        /bin/ls -t -1 -d * | head -n $count
    fi
}
share

Safe compression

Compression programs delete the original file by default. I don't like that.

alias gzip='gzip --keep'
alias bzip2='bzip2 --keep'
alias xz='xz --keep'
alias lzma='lzma --keep'

Multi-line prompt

tag() {
    TAG="${TAG} [$1]" exec zsh
}

reset_tags() {
    TAG='' exec zsh
}

color='green'
if [ "${USER}" = 'root' ]; then
    color='red'
fi

export PS1="${TAG} %B%F{yellow} *** %F{blue}%~\

%F{yellow}%(1j.[%j] .)%F{red}%(?..(%?%) )%F{${color}}%n@%m %F{blue}%# %f%b"
export RPS1='%B%F{blue}%D{%Y-%m-%d} %F{green}%D{%H:%M:%S}'
export PS2='%B%F{red}%n@%m%k %B%F{blue}%_> %b%f%k'
unset color
  • Shows the current directory in a separate line. Useful when handling a deep directory tree on a 80 column terminal.
  • Having a clock in the corner is a great thing if you use a graphical environment. This prompt shows the time. Unfortunately you have to press enter to update it.
  • You can display "tags" with environment variables. Example:

    tag 'DONT SHTUDOWN!!'
    reset_tags
    
  • The code is at least partially based on this.

History settings

dont_log() {
    HISTFILE="/dev/null" TAG="${TAG} %B%F{red}[LOGGING DISABLED]" zsh
}

if [ "${HISTFILE}" != '/dev/null' ]; then
    # history
    export HISTFILE="${HOME}/.zsh/history"
    export HISTSIZE="4096"
    export SAVEHIST="4096"

    # Don't overwrite, append!
    setopt APPEND_HISTORY

    # Write after each command
    # setopt INC_APPEND_HISTORY

    # Killer: share history between multiple shells
    setopt SHARE_HISTORY

    # If I type cd and then cd again, only save the last one
    setopt HIST_IGNORE_DUPS

    # Even if there are commands inbetween commands that are the same, still only save the last one
    setopt HIST_IGNORE_ALL_DUPS

    # Pretty    Obvious.  Right?
    setopt HIST_REDUCE_BLANKS

    # If a line starts with a space, don't save it.
    setopt HIST_IGNORE_SPACE
    setopt HIST_NO_STORE

    # When using a hist thing, make a newline show the change before executing it.
    setopt HIST_VERIFY

    # Save the time and how long a command ran
    setopt EXTENDED_HISTORY

    setopt HIST_SAVE_NO_DUPS
    setopt HIST_EXPIRE_DUPS_FIRST
    setopt HIST_FIND_NO_DUPS
fi
  • Shamelessly stolen from here.
  • I added support for explicitly disabling logging. Useful if you are dealing with programs that expect passwords as a CLI argument.
share

I like to have my bash prompt show the exit code of the previous command if it was non-zero. I also like my shell to cheer me up when I use it, so I added a bit of silliness:

smiley() {
    RC=$?
    [[ ${RC} == 0 ]] && echo ':)' || echo ":( ${RC}"
}

export PS1="\$(smiley) \h [\A] [\W] \$ "

so when I run commands, I get some nice visual feedback:

:) mycomputer [23:03] [~] $ sh -c 'exit 0'
:) mycomputer [23:03] [~] $ sh -c 'exit 11'
:( 11 mycomputer [23:03] [~] $ 

edit: this is something I put in my ~/.bashrc

share
    
Quite interesting. But, I have a doubt. Where should the code reside? –  San Feb 3 '11 at 8:23
    
In .bashrc presumably. –  Mikel Feb 3 '11 at 12:30
    
yes, that's in my ~/.bashrc –  jsbillings Feb 3 '11 at 13:35
    
Will try that.. –  San Feb 4 '11 at 6:12

better tab completion

I don't think anyone mentioned customizing Tab completion yet.

Here's what I have.

The two main things it does are:

  • each command will tab complete depending on what the command is expecting
    e.g. cd <Tab> will only suggest directories
  • ignore case
    e.g. d<Tab> will still complete Desktop and Downloads

For bash:

# custom tab completions
if type complete >/dev/null 2>&1
then
    if complete -o >/dev/null 2>&1
    then
        COMPDEF="-o complete"
    else
        COMPDEF="-o default"
    fi
    complete -a alias unalias
    complete -d cd pushd popd pd po
    complete $COMPDEF -g chgrp 2>/dev/null
    complete $COMPDEF -u chown
    complete -j fg
    complete -j kill
    complete $COMPDEF -c command
    complete $COMPDEF -c exec
    complete $COMPDEF -c man
    complete -e printenv
    complete -G "*.java" javac
    complete -F complete_runner -o nospace -o default nohup 2>/dev/null
    complete -F complete_runner -o nospace -o default sudo 2>/dev/null
    complete -F complete_services service
    # completion function for commands such as sudo that take a
    # command as the first argument but should complete the second
    # argument as if it was the first
    complete_runner()
    {
        # completing the command name
        # $1 = sudo
        # $3 = sudo
        # $2 = partial command (or complete command but no space was typed)
        if test "$1" = "$3"
        then
            set -- `compgen -c "$2"`
        # completing other arguments
        else
            # $1 = sudo
            # $3 = command after sudo (i.e. second word)
            # $2 = arguments to command
            # use the custom completion as printed by complete -p,
            # fall back to filename/bashdefault
            local comps
            comps=`complete -p "$3" 2>/dev/null`
            # "complete -o default -c man" => "-o default -c"
            # "" => "-o bashdefault -f"
            comps=${comps#complete }
            comps=${comps% *}
            comps=${comps:--o bashdefault -f}
            set -- `compgen $comps "$2"`
        fi
        COMPREPLY=("$@")
    }

    # completion function for Red Hat service command
    complete_services()
    {
        OIFS="$IFS"
        IFS='
        '
        local i=0
        for file in $(find /etc/init.d/ -type f -name "$2*" -perm -u+rx)
        do
            file=${file##*/}
            COMPREPLY[$i]=$file
            i=$(($i + 1))
        done
        IFS="$OIFS"
    }
fi

For zsh:

# set command completions
compctl -a {,un}alias
compctl -b bindkey
compctl -c command
compctl -/ {c,push,pop}d
compctl -E {print,set,unset}env
#compctl -c exec
compctl -f -x "c[-1,exec]" -c -- exec
compctl -j fg
# no -g according to zshcompctl
#compctl -g {ch}grp
compctl -j kill
compctl -c man
compctl -c nohup
compctl -u {ch}own
compctl -o {set,unset}opt
compctl -f -x "c[-1,sudo]" -c -- sudo
compctl -c {whence,where,which}
compctl -M '' 'm:{a-zA-Z}={A-Za-z}'

# make file name completion case-insensitive
zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z}'
share

make a directory and cd in one command

Most of the time I do mkdir, my next command is cd <that dir>.

This saves some typing:

# make a directory and cd to it
mcd()
{
    test -d "$1" || mkdir "$1" && cd "$1"
}

for example:

/home/mikel$ mcd somedir
/home/mikel/somedir$ 

Another thing I find useful is an easy way to make a throwaway directory. e.g. if I'm compiling a program or even if I'm trying to reproduce a problem on this site. Sometimes I might forget to clean up the directory.

# make a temporary directory and cd to it
mtd()
{
    local dir
    dir=$(mktemp -d)
    if test -n "$dir"
    then
        if test -d "$dir"
        then
            echo "$dir"
            cd "$dir"
        else
            echo "mktemp directory $dir does not exist"
        fi
    else
        echo "mktemp didn't work"
    fi
}

showing it working:

/home/mikel$ mtd
/tmp/tmp.wsnZjJ2KN6
/tmp/tmp.wsnZjJ2KN6$ 

I am relying on the system cleaning up /tmp after a reboot, but it would be possible to enhance this, e.g. make it delete the temp dir after exiting the shell.

share
    
I loved the mcd option. Nice one, Thanks. –  San Feb 3 '11 at 8:24
    
+1 I've been using my version of mcd for many years and am going to add something like mtd soon. –  maaartinus Mar 7 '11 at 7:18
    
I defined my mtd() { mcd $TMP/`date +%y%m%d-%H%M%S-%N`; }. It probably lacks a portability, but it's good enough for me. –  maaartinus Mar 7 '11 at 7:34

simple calculator

You can use $(( ... )) or expr ... to do very basic calculations, but it does integer division, e.g.

$ expr 3 / 2
1

$ expr 1.5 \* 2
expr: non-integer argument

A better way is to use bc.

# do some floating point arithmetic
calc()
{
    echo "scale=3; $*" | bc
}

then:

$ calc 3 / 2
1.500
$ calc 1.5 \* 2
3.0
share
1  
My calculator is alias py='PYTHONSTARTUP=~/.pythonstartup python' with from math import *; in that file. The integer-division problem remains unsolved, but it's way more usable for more complex operations. –  maaartinus Mar 7 '11 at 7:14

(Community wiki, so each trick belongs in a separate answer.)

search your history for all the ways you ran a command

You might already know about Ctrl+R, but this way is much smoother IMHO.

Set up Alt+P to search history for commands that start with what you already typed.

e.g. ls Alt+P, Alt+P , Alt+P will search backwards thru all your ls commands.

You need to put this in your /etc/inputrc or .inputrc for bash:

$if mode=emacs
"\ep": history-search-backward
"\en": history-search-forward
$endif

and this in your .zshrc for zsh:

bindkey -M emacs '^[p' history-beginning-search-backward
bindkey -M emacs '^[n' history-beginning-search-forward

You could even go one step further and make the Up arrow do this.

share

(Community wiki, so each trick belongs in a separate answer.)

safe logout

Ctrl+D is the easiest way to exit the shell, but if you still have jobs running, it will happily exit the shell anyway. By default, this means all the programs you were running from inside that shell will be killed.

Some shells will only let you log out after pressing Ctrl+D twice, but it's still too easy to do that accidentally.

So instead, add this to .bashrc or .zshrc or whichever config file you prefer.

alias x='_exit'

# prevent running "exit" if the user is still running jobs in the background
# the user is expected to close the jobs or disown them
_exit()
{
    case $- in *m*)
        # this way works in bash and zsh
        jobs | wc -l | grep -q '^ *0 *$'
        if test $? -eq 0
        then
            command exit "$@"
        else
            jobs
        fi
        ;;
    *)
        command exit "$@"
        ;;
    esac
}
share

Adding the non-zero return value of the last command is a great idea. I think the original poster was specifically asking about .profile/.cshrc/.bashrc. It's worth mentioning the list of other commonly customized RC files, but I would stick to just shell customizations for this question.

I also recently added a flag in my prompt that shows up when the shell is running under screen. It uses the solaris "ptree" command to search ancestor processes, but you could use the "pstree" command on Linux to do the same thing.

SCREEN=""
if [ -f /usr/bin/ptree ]; then
   if ptree $$ | grep -v grep | grep -w screen > /dev/null 2>&1; then
       SCREEN="SCREEN "
   fi
fi

It took me a few minutes to figure out how to embed the return code of the last command, so I'll post it here.

PROMPT_COMMAND='if [ "$?" = 0 ]; \
        then RC=""; \
        else RC="RV=$? "; fi; PS1="% ${SCREEN}\h $RC\w\n% "'

I'm sure that could be made more beautiful. :-)

Future tip, be careful about reading $? after using "if [". If the left bracket is a built-in it will not override the value of $?. But if you use a shell where [ is not built-in, then it will reset the value of $? after testing. It's safer to assign $? into a temporary variable right away and then test that variable.

share
    
Your answer should probably be a comment... Like this! –  VxJasonxV Jan 31 '11 at 9:08

I mess up with my bashrc since i use terminal a lot (it makes me learn fast and learn interesting stuff to use as well as interesting tools). I ususally define a lots of functions in my bashrc. Examples:

Extract archives:

extract () {
libextract () {
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" ;;
    *.7z) 7z x "$1" ;;
    *) echo "$1 ne moze biti raspakovan!" ;;
  esac
else
  echo "$1 nije validan fajl"
fi
}
 echo "Unesite putanju do direktorijuma u kome se nalaze arhive: " && read dir && dirprovera && cd $dir
  for f in *
    do
      mkdir ./$f-raspakovano && cd ./$f-raspakovano
      libextract ./../$f
      cd ./../
    done
  tipka
}

rename files and folders:

frename () {
if [ $# -gt 0 ]
then
 dir="$(echo $1)"
  dirprovera
  cd $dir
  for f in *
    do
      mv "$f" "`echo "$f" | tr -s " " "_" | tr "A-Z" "a-z"`" 2>/dev/null &
    done
  tipka
else
 echo "Upotreba: frename [direktorijum]" >&2
fi
}

and like this for spliting large files into several small ones:

fsplit () {
if [ $# -gt 1 ]
then
 file="$(echo $1)"
 SIZE="$(echo $2)"
 PREFIX="$(echo $3)"
 if [ -z "$PREFIX" ]; then PREFIX="fsplit"; fi
  fileprovera
  split -d -a 3 -b $SIZE $file "$PREFIX-part-" || echo "Doslo je do greske!"
  tipka
else
 echo "Upotreba: fsplit [fajl] [velicina] [prefix]
Za velicinu se koriste m (MB), g (GB) ili k (KB) (15m, 650kb, 4.7g...)

Prefiks moze sadrzati brojeve, slova, i crtice (primer: moj_pre-fiks)
Ukoliko ne unesete prefiks isti ce biti dodeljen automatski u sledecem formatu:
  fsplit-part-XXX
gde XXX predstavlja broj dela fajla (001, 005, 189...)" >&2
fi
}

Also i edited a lot of aliases since i find that it's far more easier to use one command with arguments as default in some cases (like in ls, grep and small commands) then to type all that down every time.

share

.zshrc:

alias l='ls -CF'
alias ll='ls -ClhF'
alias la='ls -CaF'
alias lla='ls -CalhF'
alias l.='ls -CAF --ignore=\*'
alias ll.='ls -CAlhF --ignore=\*'
alias t='tree -C'

PS1=$'%{\e[0;33m%}%m %{\e[32;1m%}%~ %{\e[0;31m%}%#%{\e[m%} '

bindkey '^[[3~' delete-char

export GREP_OPTIONS="--color"

.xmodmaprc:

clear lock
keycode 9 = Caps_Lock ISO_Next_Group Caps_Lock ISO_Next_Group
keycode 66 = Escape NoSymbol Escape
add lock = Caps_Lock

(Swaps Escape and Caps Lock keys).

share
    
+1 for remapping of keys, my Caps Lock is mapped to Return, WHO NEEDS CAPS LOCK ANYWAY? –  wag Jan 30 '11 at 9:58
1  
I'm a Vim user. It's typical for Vim users, to map Escape to Caps Lock. Emacs user tend to map Control to Caps Lock. –  polemon Jan 30 '11 at 15:36

If you can TURN ON AUTOCOMPLETE AND FILE NAME SPELLING CORRECTION! That's probably the two things that will save you the most time. Then, learn to use them - Bash and Zsh have tab-completion. Ksh has an inefficient escape-backslash, so I'd recommend against Ksh.

I use Zsh, but aliases like this would work in almost any shell except Csh:

alias l='ls -FC --color=tty'
alias ls='ls -FC --color=tty'
alias h=history
alias m=more
alias vi=vim
alias cx='chmod +x'

It seems like an alias for 'ps' should be in there, but I find myself using 'ps' in a wide variety of ways, and I haven't found anything so far.

In Zsh, set up your RPROMPT (not a typo!) variable:

RPROMPT='%d'

The entire directory appears on the right side of the command line, ready for cutting-n-pasting. More on that later.

You should use a properly compiled modern Vim, because of the ability to have multiple vim-windows into a file, and multiple buffers. Your .vimrc could have things like this in it:

set mouse=c
set ml
set mls=5
set nowrap
set nobackup
set nonu
set showmatch
set tabstop=4
set shiftwidth=4
set showmode
set showcmd
set ruler
set notextauto
set laststatus=2
set mps=(:),{:},[:],<:>
set modelines=0

A lot of those are personal preference, but I do happen to believe that 8-space tabs make code less readable, and there's a study floating around to prove it.

Also, the "mouse=c" is important. You shouldn't be using your mouse to move around inside a file. Taking your hands off the keyboard, touching the mouse and them moving them back is slow. Use "hjkl" cursor movement, and other keyboard paging and cursor movement keys.

If you're using X11, you should do a few things to your Xterm configuration. This comes out of my .Xresources file:

XTerm*VT100.scrollBar: true
XTerm*VT100.saveLines: 1000
XTerm*VT100.cutNewLine: false 
XTerm*VT100.cutToBeginningOfLine: false
XTerm*VT100.charClass: 33:48,35:48,37:48,42:48,45-47:48,64:48,95:48,126:48
XTerm*VT100*translations: #override \n\
    <Key>F2: insert-selection(PRIMARY,CUT_BUFFER0)

Give Xterm a scrollbar by default, save 1000 lines of text in the buffer, that's pretty standard.

The charClass directive makes a "word" include things like '.', '/' and '*'. Double clicking on any part of a '/'-separated file name, and you get the whole thing, less ':' characters.

cutToBeginningOfLine works with the Zsh RPROMPT above. Triple click on the path of the current working directory that appears on the RHS of your command line, and you pick up only the path: the copy stops at the beginning of the word. Highly efficient once you're used to it.

The above X resources also makes the into a paste key. That way, once you've copyed (probably using the mouse) you can paste without moving your hand back to the mouse to click.

share
    
FWIW, the filename completion is Esc``Esc or Esc``= in ksh, and Tab works in ksh93. Just in case anyone is stuck with it or prefers it. –  Mikel Feb 2 '11 at 21:35

.vimrc

save file with root permissions by typing w!!:

cmap w!! w !sudo tee % > /dev/null


.bashrc

Don't bother with devices or binary files when greping:

alias grep='grep --color=auto --binary-files=without-match --devices=skip'


Share code on the web (like pastebin, but simpler) by cat 1337.sh | webshare

alias webshare='curl -F "sprunge=<-" http://sprunge.us | xclip'

It gives back a short url in your clipboard; you can append ?whatever-lang to the returned URL to have it syntax highlighted and lines numbered.


.inputrc

Use vi mode in everything that uses the readline library (many programs):

set editing-mode vi
set keymap vi
share
    
+1 for the .vimrc –  chris Feb 2 '11 at 20:06
    
Great tips which I never knew. –  San Feb 3 '11 at 8:11
  • bashrc: I'm a zsh user, so I have a few lines in my bashrc that start zsh if it is available on a system.
  • zshrc: Instead of copying my zshrc from something like grml (though there zshrc is pretty good, so if you don't want to roll your own theirs is probably one of the best) I write my own zshrc.
    • I have a customized prompt. Among some other things it shows the return code of the last command if it was unequal to 0.
    • I have some aliases. Because I have accounts on quite a number of servers I sometimes have to perform checks for which version of a command is available on a system and set the alias accordingly.
    • I set my PATH variable.
    • I set some other environment variables (for example $EDITOR)
  • vimrc: I'm a vim user, so I have a customized and a customized color scheme.
  • screenrc: I use GNU screen to avoid having to open multiple terminals and to preserve history while not being logged in, so I have my own screenrc.
share

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